如何无需显式指定模板参数定义模板结构体常量变量?
问题与需求
现有如下结构体和类定义,用于存储类成员函数指针:
template <typename R> struct Foo { R ref; int info; }; class Bar { public: void* run(); };
希望创建Foo类型的常量变量时,无需显式指定模板参数,直接用初始化列表完成初始化(如下方第一行代码),而不是必须写出冗长的成员函数指针类型(第二行可行但不够简洁):
const Foo theVar {&Bar::run, 0x1000}; // 期望的简洁写法,但原代码编译不通过 const Foo<void (Bar::*)()> theVar {&Bar::run, 0x1000}; // 可行但写法繁琐
使用模板的原因是类成员函数指针无法直接转换为void*,只能通过模板来存储其原始类型。同时要求该变量必须在链接阶段可见,不能在运行时赋值,模板是当前可行的实现方式,但显式指定模板参数不够简洁,易引发维护问题。
解决方法
方法1:C++17及以上 - 类模板实参推导(CTAD)
C17引入了类模板实参推导(Class Template Argument Deduction, CTAD),编译器可根据初始化列表中的参数自动推导模板类型。只需确保编译器开启C17或更高版本的编译选项,你的期望写法就能直接编译通过:
const Foo theVar {&Bar::run, 0x1000}; // C++17+ 编译正常
编译器会自动识别&Bar::run的类型为void (Bar::*)(),并将其作为Foo的模板参数R。
方法2:兼容C11/C14 - 辅助推导函数
如果需要兼容更早的C++标准,可以编写一个简单的辅助函数来推导模板类型:
template <typename R> Foo<R> make_foo(R ref, int info) { return {ref, info}; }
然后通过该函数创建变量,编译器会自动推导R的类型:
const auto theVar = make_foo(&Bar::run, 0x1000);
这种方式同样能避免显式写出冗长的成员函数指针类型,同时兼容C++11及以上标准。
内容的提问来源于stack exchange,提问作者KevinN
相关产品推荐
相关产品推荐

