假设我有以下一堆文件:
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;
}
main.cpp:
#include <Client.h>
int main(int argc, char**args) {
Client c;
return 0;
}
GenericMap
表示没有前向声明的模板类。对于某些用户,SpecialMap
的完全专业化版本GenericMap
应该足够,其中使用typedef
易于使用。
现在Client
使用内部SpecialMap
,但是头文件只应声明SpecialMap
的转发声明。
不幸的是,以下文件无法编译。不知何故,发布的前向声明就足够了。什么是正确的?
我很抱歉很长的列表,但这是我能想到的最小的非工作示例。
答案 0 :(得分:4)
在评论中,您澄清说您实际上并未提及C ++专业化。你只是询问typedef:
typedef GenericMap<std::string, int, std::map> SpecialMap;
这就是故事的结尾。这声明SpecialMap
是typedef
,类型别名。需要使用SpecialMap
的任何翻译单元都需要包含此类型定义。而且只有这个定义。没有别的事情需要做。它不需要以任何其他方式声明。这是一个别名。使用其基础类型搜索/替换typedef
别名会产生相同的精确结果。在一个翻译单元中声明的typedef
仅在该翻译单元中可见。其他翻译单元没有捷径可以将typedef
导入其范围。
在您的Client.h中:
#include <Special.h>
您定义此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
模板类,仅限于此在这里向前宣布。