7

假设我有以下一堆文件:

Generic.h:复杂的模板类

#pragma once

template<typename K, typename V, template<typename Key, typename Value, typename ...> typename C>
struct GenericMap
{
    C<K, V> key;
};

Special.h:定义提到的模板类的完全专用版本,简化了易用性。

#pragma once

#include "Generic.h"
#include <string>
#include <map>

typedef GenericMap<std::string, int, std::map> SpecialMap;

Client.h:使用SpecialMap和定义前向声明的客户端。

#pragma once

class SpecialMap; // Wrong forward declaration

struct Client {
    Client();
    SpecialMap* map;
};

Client.cpp:客户端代码可能知道Generic.h并且Special.h

#include "Client.h"
#include "Special.h"

Client::Client()
{
    map["343"] = 2;
}

主.cpp:

#include <Client.h>

int main(int argc, char**args) {
    Client c;
    return 0;
}

GenericMap表示没有前向声明的模板类。对于某些用户来说,完全专用SpecialMapGenericMapshould 版本就足够了,为了方便使用,这里使用了 a typedef

现在在Client内部使用SpecialMap,但头文件应该只为SpecialMap.

不幸的是,以下文件将无法编译。不知何故,张贴的前向声明就足够了。什么是正确的?

对于冗长的列表,我很抱歉,但这是我能想到的最小的非工作示例。

4

1 回答 1

8

在评论中,您澄清说您实际上并不是指 C++ 专业化。您只是在询问 typedef:

typedef GenericMap<std::string, int, std::map> SpecialMap;

这几乎就是故事的结局。这声明SpecialMap为 a typedef,类型别名。任何需要使用的翻译单元都需要SpecialMap包含这个类型定义。而且只有这个定义。没有其他事情需要做。它不需要以任何其他方式声明。它是一个别名。typedef使用其基础类型搜索/替换别名会产生相同的确切结果。在一个翻译单元中声明的Atypedef仅在该翻译单元中可见。其他翻译单位没有捷径可将其typedef导入其范围。

在您的 Client.h 中:

#include <Special.h>

这就是你定义 this 的地方typedef,这是引入这个定义的唯一方法。

然而,这也可能typedef是一个较大的头文件的一部分的情况,并且最好单独拉入 typedef。这可以通过仅包含以下内容的头文件来完成:

#include <string>
#include <map>

template<typename K, typename V,
        template<typename Key, typename Value, typename ...>
             typename C> struct GenericMap;

typedef GenericMap<std::string, int, std::map> SpecialMap;

typedef这将是定义别名所需的最低限度。任何实际需要使用它的东西,#include不仅需要这个头文件,还需要你的Generic.h头文件,它实际上定义了GenericMap模板类,这里只是前向声明的。

于 2016-07-07T12:22:55.033 回答