如何将成员函数模板作为模板参数传递?
问题:将模板静态成员函数作为模板参数传递
背景代码
我有如下静态模板成员函数:
class Foo { public: template<typename... Args> static void bar(const Args&... args) { /* code */ } };
希望将它作为模板参数传递给Example类的doStuff成员函数,初始的doStuff定义如下:
class Example { public: template<typename... Args, typename T> void doStuff(const Args&... args) { T(args...); } };
尝试的解决方案
我尝试过两种写法,第一种:
class Example { public: template<typename... Args, typename C, void (C::*F)(Args&...)> void doStuff(const Args&... args) { (C::F)(args...); } };
后来考虑到bar的参数是const Args&,调整了签名:
template<typename... Args, typename C, void (C::*F)(const Args&...)>
但都没有解决问题。我怀疑是没有为参数F定义正确的模板,也考虑过用lambda,但不想采用这种方式。
最小可复现示例
class Foo { public: template<typename... Args> static void bar(const Args&... args) { /* code */ } }; class Example { public: template<typename... Args, typename C, void (C::*F)(Args&...)> void doStuff(const Args&... args) { (C::F)(args...); } }; class SomeClass { public: Example ex {}; template<typename... Args> void someFunc(const Args&... args) { ex.doStuff<Args..., Foo, &Foo::bar>(args...); } }; int main() { SomeClass sc {}; sc.someFunc("Some ", "Arguments ", "Here"); return 0; }
问题分析与解决
核心问题是:&Foo::bar是一个模板函数,在未显式实例化前没有具体的函数地址,而原模板参数只接受普通的成员函数指针,无法匹配模板函数的地址。以下是几种可行的解决方案:
方案1:使用C++17 auto模板参数(推荐)
利用C++17引入的auto模板参数,可以直接接受函数指针,让编译器自动推导类型:
class Example { public: // 调整模板参数顺序,让编译器先推导Args template<auto F, typename... Args> void doStuff(const Args&... args) { F(args...); } };
调用时无需手动指定Args,编译器会自动推导:
template<typename... Args> void someFunc(const Args&... args) { ex.doStuff<&Foo::bar>(args...); }
这里&Foo::bar会被编译器自动实例化为匹配Args类型的版本,完美适配需求。
方案2:显式实例化模板函数指针
如果不支持C++17,可以显式指定Foo::bar的模板参数,得到具体的函数指针后再传递:
class Example { public: template<typename... Args, typename C> void doStuff(void (C::*F)(const Args&...), const Args&... args) { (C::*F)(args...); } };
调用时显式实例化Foo::bar:
template<typename... Args> void someFunc(const Args&... args) { ex.doStuff<Args..., Foo>(&Foo::bar<Args...>, args...); }
因为静态成员函数的指针也可以当作普通函数指针使用,所以也可以简化doStuff的参数:
class Example { public: template<typename... Args> void doStuff(void (*F)(const Args&...), const Args&... args) { F(args...); } }; // 调用时: ex.doStuff(&Foo::bar<Args...>, args...);
方案3:模板模板参数传递
另一种思路是直接传递模板本身,而非函数指针:
class Example { public: template<typename... Args, template<typename...> class F> void doStuff(const Args&... args) { F<Args...>(args...); } };
调用时传递Foo::bar模板:
template<typename... Args> void someFunc(const Args&... args) { ex.doStuff<Args..., Foo::bar>(args...); }
注意这种写法对编译器的兼容性要求较高,部分旧编译器可能不支持将成员模板作为模板模板参数传递。
内容的提问来源于stack exchange,提问作者Luh0
相关产品推荐
相关产品推荐

