可变参数模板的std::hash特化在不同GCC版本中的报错及正确性咨询
问题解答:移除
template<>后的写法符合C++标准且完全正确 你遇到的问题本质是类模板部分特化与全特化的语法区别,下面详细解释:
核心原因:你要做的是部分特化,而非全特化
std::hash的原型是一个单参数类模板:
template<class T> struct hash;
你想要特化的是所有foo::Pi<Types...>类型的hash版本——这属于类模板的部分特化(用模板参数Types...匹配原模板的参数T,覆盖所有foo::Pi的可变参数实例),而非全特化(全特化需要指定T的具体类型,比如foo::Pi<int, std::string>这种确定的类型)。
根据C++标准:
- 全特化类模板时,才需要前置
template<>(比如template<> struct hash<foo::Pi<int>> {};) - 部分特化类模板时,不需要前置
template<>,直接写用于特化的模板参数列表即可
你原来的代码中,前置的template<>会让编译器误以为你要做全特化,但后面又跟了template<typename...Types>的参数列表,这就产生了语法冲突,所以GCC 8.3.1(更严格遵循标准)会报错;而GCC 4.8.3对模板语法的检查不够严格,允许了这种不符合标准的写法。
正确写法验证
移除template<>后的代码是完全符合C++标准的:
namespace foo { template<typename ...Types> class Pi { }; } namespace std { template<typename ...Types> struct hash<foo::Pi<Types...>> { std::size_t operator()( const foo::Pi<Types...>& s ) const noexcept { return 0; } }; } int main() { return 0; }
这段代码是对std::hash针对用户自定义类型foo::Pi<Types...>的合法部分特化,C++标准明确允许对std命名空间的模板进行这种针对用户自定义类型的特化。
内容的提问来源于stack exchange,提问作者greywolf82
相关产品推荐
相关产品推荐

