C++模板偏特化:如何让任意指针类型实例化const版本避免重复模板
问题原因
你写的泛化指针偏特化会触发无限递归模板实例化:
当实例化Foo<int*>时,匹配template<class T> struct Foo<T*>偏特化,需要先实例化基类Foo<const int*>;但const int*本身也是指针类型,同样会匹配这个偏特化,推导T = const int,又需要实例化基类Foo<const (const int)*>也就是Foo<const int*>,循环无法终止,编译器会直接报错。
解决方案
核心思路是给偏特化增加约束:仅当指针指向的类型不是const时,才匹配该偏特化、复用const版本的实现;指针指向const的场景直接使用主模板,终止递归。
C++11 及以上通用实现
需要给主模板增加一个默认的空模板参数用于SFINAE约束,不影响原有调用逻辑:
#include <iostream> #include <type_traits> // 主模板新增默认void参数,原有调用方式完全兼容 template<class T, typename = void> struct Foo { static void bar() { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; // 仅对指向非const类型的指针生效的偏特化 template<class T> struct Foo<T*, std::enable_if_t<!std::is_const<T>::value>> : Foo<const T*> {}; // 如果需要兼容指针本身带const的场景(比如char* const),增加以下偏特化 template<class T> struct Foo<T* const, std::enable_if_t<!std::is_const<T>::value>> : Foo<const T*> {}; int main() { Foo<char*>::bar(); // 复用Foo<const char*>实现 Foo<int*>::bar(); // 复用Foo<const int*>实现 Foo<const double*>::bar();// 直接使用主模板实例,终止递归 Foo<char* const>::bar(); // 也复用Foo<const char*>实现 }
C++20 简化实现
用requires约束不需要修改主模板,语法更简洁:
#include <iostream> #include <type_traits> template<class T> struct Foo { static void bar() { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; // 仅指向非const类型的指针匹配该偏特化 template<class T> requires (!std::is_const_v<T>) struct Foo<T*> : Foo<const T*> {}; // 兼容指针本身带const的场景 template<class T> requires (!std::is_const_v<T>) struct Foo<T* const> : Foo<const T*> {}; int main() { Foo<char*>::bar(); Foo<int*>::bar(); Foo<const double*>::bar(); }
验证效果
运行代码后,所有非const指针的bar()调用都会输出对应const指针版本的函数签名,说明确实复用了模板实例,不会生成重复代码。
内容的提问来源于stack exchange,提问作者Voko
相关产品推荐
相关产品推荐

