如何让C++模板接受任意类型的常量值?
在C++中实现接受任意类型常量值的模板
你希望实现一个无需显式指定类型、仅传入常量值就能实例化的模板,替代现有需要同时指定类型和值的Foo<T, Element>写法,以及不够优雅的宏方案。
现有实现代码
using namespace std; typedef enum { E11, E12} E1; typedef enum { E21, E22} E2; void a(E1 e) { cout<<"something from E1"<<endl; } void a(E2 e) { cout<<"something from E2"<<endl; } template <typename T, T Element> class Foo { public: void foo() { a(Element); }; }; // 不希望使用的#define解决方案 #define _Foo(x) Foo<decltype(x), x> int main() { Foo<E1, E12> d1; d1.foo(); Foo<E2, E22> d2; d2.foo(); // 使用宏解决方案 _Foo(E12) d3; d3.foo(); _Foo(E22) d4; d4.foo(); }
期望的模板形式
你希望写出如下简洁的模板:
template <AnyTypeAcceptor Element> class Foo { public: void read() { a(Element); }; }; int main() { Foo<E22> d1; d1.read(); Foo<E11> d2; d2.read(); }
解决方案:C++17及以上的auto非类型模板参数
从C++17开始,语言原生支持auto非类型模板参数,可以直接实现你想要的效果,无需依赖宏或冗余的类型声明。修改后的代码如下:
#include <iostream> using namespace std; typedef enum { E11, E12} E1; typedef enum { E21, E22} E2; void a(E1 e) { cout<<"something from E1"<<endl; } void a(E2 e) { cout<<"something from E2"<<endl; } // 使用auto自动推导常量值的类型 template <auto Element> class Foo { public: void read() { a(Element); }; }; int main() { Foo<E22> d1; d1.read(); // 输出: something from E2 Foo<E11> d2; d2.read(); // 输出: something from E1 }
核心说明
template <auto Element>中的auto会在编译期自动推导传入常量值的具体类型,完全替代了原来需要显式声明typename T, T Element的写法。- 该特性支持所有符合非类型模板参数要求的类型,包括枚举、整数、指针、引用等,完全覆盖你的场景需求。
C++20的扩展支持
C20进一步放宽了非类型模板参数的限制,允许使用满足特定条件的用户自定义类型作为模板参数,如果你需要处理更复杂的常量值,C20会提供更多灵活性。
旧C++版本的替代方案
如果项目仍在使用C17之前的版本,没有直接的语法支持实现这种简洁写法,此时宏方案是最接近的替代选择。你也可以尝试封装辅助模板结合类型推导优化,但本质上无法达到C17及以上版本的简洁程度。
内容的提问来源于stack exchange,提问作者knight37x
相关产品推荐
相关产品推荐

