正确的完全专业化模板的前向声明 类

Correct forward declaration of fully specialized template classes

假设我有以下一堆文件:

Generic.h: 复杂模板 class

#pragma once

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

Special.h: 定义上述模板的完全专用版本 class,简化易用性。

#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.hSpecial.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 表示没有前向声明的模板 class。对于某些用户来说,SpecialMapGenericMap 完全专业化的版本就足够了,为了便于使用,使用了 typedef

现在Client在内部使用SpecialMap,但是头文件应该只为SpecialMap声明一个前向声明。

不幸的是,以下文件将无法编译。以某种方式发布的前向声明就足够了。正确的是什么?

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

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

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

故事到此就差不多结束了。这将 SpecialMap 声明为 typedef,一个类型别名。任何需要使用 SpecialMap 的翻译单元都需要包含这个类型定义。而且只有这个定义。不需要做任何其他事情。它不需要以任何其他方式声明。它是一个别名。 typedef 别名的 search/replace 及其基础类型产生完全相同的结果。在一个翻译单元中声明的 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 模板 class,这只是在此转发声明。