You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将成员函数模板作为模板参数传递?

问题:将模板静态成员函数作为模板参数传递

背景代码

我有如下静态模板成员函数:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:20:20