我可以专门研究前向声明的模板吗?

jas*_*mar 5 c++ templates template-meta-programming

我可以专门研究前向声明的模板吗?例如:

template <typename T> class A;

template <>
class A<char> {
    char a[1000];
};

int main()
{
    [[maybe_unused]] A<char> a;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我想达到什么目标?

正如我们所知,我们必须专门std::hash将它与一些基于哈希表的类型一起使用。标准特化std::hash需要<functional>在头文件中包含然后特化它。我在很多地方都用到了这个头文件,编译时间<functional>挺大的。所以我想将我的专业转移到源(cpp)文件。

my_type.hpp:

class my_type {/*...*/};

namespace std {

template <typename T>
struct hash;

template <>
struct hash<my_type>
{
    size_t operator()(my_type m) const;
};
} // namespace std
Run Code Online (Sandbox Code Playgroud)

my_type.cpp:

#include "my_type.hpp"
#include <functional>
namespace std {
size_t std::hash<my_type>::operator()(my_type v) const
{
    return std::hash<decltype(v.value())>{}(v.value());
}
} // namespace std
Run Code Online (Sandbox Code Playgroud)

此解决方案有效,但就 ISO 标准而言是否合法?

编辑/注意:它不适用于 libc++(clang std 实现),因为它定义std::hashstd::__1::hash, where __1is inline namespace。这部分回答了这个问题。

Sto*_*ica 6

一般的问题A是,是的,这是允许的。显式特化与主模板不相交。无论主要是如何定义的,它都可以定义为完整的或不完整的。

至于你更具体的问题std::hash,不是不行。你违反了

[命名空间.std]

1除非另有说明,如果 C++ 程序向命名空间std或命名空间内的命名空间添加声明或定义,则它的行为是未定义的std

2除非明确禁止,否则程序可以将任何标准库类模板的模板特化添加到命名空间, std前提是 (a) 添加的声明依赖于至少一个程序定义的类型,并且 (b) 特化满足标准库对原始模板。

前向声明std::hash不是依赖于用户定义类型的特化声明。这是属于第 1 段规范的简单声明。没有允许std::hash在标准中的任何其他地方转发声明的措辞。所以这是未定义的行为。