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

Correct forward declaration of fully specialized template classes

本文关键字:专用 声明      更新时间:2023-10-16

假设我有以下一堆文件:

泛型:复杂的模板类

#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;
};

客户端.cpp:客户端代码可能知道Generic.hSpecial.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表示没有前向声明的模板类。对于某些用户来说,完全专业化的版本SpecialMap GenericMap就足够了,为了便于使用,使用typedef

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

遗憾的是,以下文件将无法编译。不知何故,发布的前瞻声明就足够了。什么是正确的?

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

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

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

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

在您的客户端中:

#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模板类,这里只是向前声明的。