C++类型别名初始化全特化模板时存在歧义,求解决办法
问题
用类型别名作为模板参数初始化模板类时,所有指向同一底层类型的别名都会匹配到同一个特化版本,导致代码行为不符合预期。比如下面的代码里,Type1和Type2都是size_t的别名,初始化SomeClass<Type2>时会匹配到SomeClass<Type1>的特化,进而导致doSomething()无法调用。
#include <iostream> using Type1 = size_t; using Type2 = size_t; template <class Type> class SomeClass { public: void doSomething() { } }; template <> class SomeClass<Type1> { public: }; int main() { SomeClass<Type1> someClass1; // 初始化特化版本 SomeClass<Type2> someClass2; // 实际也匹配到SomeClass<Type1>的特化 someClass2.doSomething(); // 编译报错,特化版本无该方法 }
解决办法
方法1:用标签类区分别名
给每个类型别名创建空标签类,作为模板的额外参数,让不同别名对应不同的模板实例:
#include <iostream> // 定义不同的标签类 struct Tag1 {}; struct Tag2 {}; // 模板添加标签参数 template <class Type, class Tag> class SomeClass { public: void doSomething() { } }; // 特化size_t+Tag1的版本 template <> class SomeClass<size_t, Tag1> { public: }; using Type1 = size_t; using Type2 = size_t; int main() { SomeClass<Type1, Tag1> someClass1; // 匹配特化版本 SomeClass<Type2, Tag2> someClass2; // 匹配通用版本 someClass2.doSomething(); // 正常调用 }
方法2:自定义强类型包装
把底层类型包装成自定义结构体,让每个“别名”成为独立的类型,而非同一类型的别名:
#include <iostream> // 自定义强类型,包装size_t struct Type1 { size_t value; // 可按需添加运算符重载,保持与size_t的兼容性 }; struct Type2 { size_t value; }; template <class Type> class SomeClass { public: void doSomething() { } }; // 特化Type1版本 template <> class SomeClass<Type1> { public: }; int main() { SomeClass<Type1> someClass1; // 特化版本 SomeClass<Type2> someClass2; // 通用版本 someClass2.doSomething(); // 正常调用 }
方法3:带标签的模板别名
通过模板别名结合非类型模板参数,让不同的别名对应不同的模板实例:
#include <iostream> // 带标签的模板别名 template <int Tag> using TaggedSizeT = size_t; using Type1 = TaggedSizeT<1>; using Type2 = TaggedSizeT<2>; template <class Type> class SomeClass { public: void doSomething() { } }; // 特化TaggedSizeT<1>的版本 template <> class SomeClass<TaggedSizeT<1>> { public: }; int main() { SomeClass<Type1> someClass1; // 特化版本 SomeClass<Type2> someClass2; // 通用版本 someClass2.doSomething(); // 正常调用 }
内容的提问来源于stack exchange,提问作者Miroslav Krajcir
相关产品推荐
相关产品推荐

