【问题标题】:Passing a member function pointer as an argument to a template method将成员函数指针作为参数传递给模板方法
【发布时间】:2020-10-26 21:09:08
【问题描述】:

我正在尝试编写一个接受成员函数指针作为参数的模板化方法。

这是一个示例类,包括我最近尝试编写的模板方法:

class MyClass
{
public:
   int myMethod() { return 1; }

   template<typename T> 
   T call(std::function<T(MyClass*)> m)
   {
      return m(this);
   }
};

我的目标是能够做到以下几点(或语法上非常相似的事情):

MyClass m;
auto result = m.call(&MyClass::myMethod);

到目前为止,我的上述尝试,我可以做到:

MyClass m;
std::function<int(MyClass*)> f = &MyClass::myMethod;
auto result = m.call(f);

我很惊讶我什至无法将其包装成一行。 m.call(&amp;MyClass::myMethod) 这不会编译。为什么?

我确信有办法获得我想要的行为,所以任何帮助将不胜感激!

【问题讨论】:

  • 运行代码时得到什么输出?
  • 关于推断T的类型我想。这显式指定T,编译auto result = m.call&lt;int&gt;([](MyClass* h){return h-&gt;myMethod();});
  • 当我用我想要的语法编译时,我得到candidate template ignored: could not match 'function&lt;type-parameter-0-0 (MyClass *)&gt;' against 'int (MyClass::*)()' 我试图避免指定返回类型等,希望尽可能自动。从技术上讲,我可以做到这一点,但它的语法很糟糕:m.call(std::function&lt;std::result_of&lt;decltype(&amp;MyClass::myMethod)(MyClass)&gt;::type(MyClass*)&gt;(&amp;MyClass::myMethod))
  • 为什么在成员函数模板调用中调用“m”时将“this”作为参数传递。一世。 e m(这个) ;

标签: c++ c++11 templates lambda std-function


【解决方案1】:

显然它不能推断出T(来自一个非常推断的ctor参数的模板参数)。

如果您的目标是简单地在一次调用中完成,您可以将方法定义更改为类似

    template<class F> auto call(F &&f) {
        return std::invoke(std::forward<F>(f), this);
    }

【讨论】:

    【解决方案2】:

    我很惊讶我什至无法将它包装成一行。 m.call(&amp;MyClass::myMethod) ...这不会编译。为什么?

    成员函数指针有以下类型

    <return-type>(ClassType::*)(<args>)<specifiers-if-any>
    

    意思是&amp;MyClass::myMethod有类型

    int(MyClass::*)(void)
    

    这不等于std::function&lt;int(MyClass*)&gt;类型,编译器不能直接推导出来,所以编译器出错。

    但是,如果我们显式提及模板类型,则可以推断为std::function&lt;int(MyClass*)&gt;some type erasur overheads。这意味着您可以明确提及模板参数,如下所示:

    /* const */ int result = m.call<int>(&MyClass::myMethod);    // works!
    //                             ^^^^^^ -> mention T == int here!
    

    (See Live Demo)


    我确信有办法获得行为[...]

    如果你不使用std::function 而不是普通的(模板化的)成员函数指针类型,这将起作用。

    template<typename T>
    T call(T(MyClass::* m)())
    {
       return (this->*m)();
       // or
       // std::invoke(m, this); // in C++17
    }
    

    现在你可以

    /* const */ int result = m.call(&MyClass::myMethod);
    

    (See Live Demo)


    如果语法令人困惑,您可以像这样为成员函数指针提供模板类型别名。

    class MyClass 
    {
       // template type alias
       template<typename T> using MemFunctionPtrT = T(MyClass::*)();
    public:
       // other codes
    
       template<typename T>
       T call(MemFunctionPtrT<T> m) // use the alias type like
       {
          return (this->*m)();
          // or
          // std::invoke(m, this); // in C++17
       }
    };
    

    【讨论】:

    • 谢谢,这也是如何正确定义模板函数以接受成员函数指针的有用说明!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 2020-04-29
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多