如何返回使用参数包定义的成员函数的 std::function 对象?

Posted

技术标签:

【中文标题】如何返回使用参数包定义的成员函数的 std::function 对象?【英文标题】:How to return a std::function object of member function which define with parameter packs? 【发布时间】:2019-11-15 17:21:47 【问题描述】:

我想定义一个成员函数,它可以返回另一个成员函数的std::function 对象。一般来说,这很容易。但是如果那个成员函数是由参数包定义的,我就不知道怎么做了。

我写了一些代码如下,

class Example 
  public:

  template<typename... Args>
  double getSome(Args... args) 
    // do something
  

  template<typename... Args>
  std::function<double(Args...)> getSomeFun() 
        return std::bind(&Example::getSome<Args...>, this);
  

;

这看起来是正确的,不幸的是。当我在main() 方法中调用getSetArgsFunction() 时,我得到了很多错误信息。在main()方法,我的代码如下,

int main() 
  Example e;
  e.getSomeFun()(1.0, 2.0, 3.0);

我尝试编译它,但是gcc打印一些错误如下,

error: no match for call to ‘(std::function<double()>) (double, double, double)’

那么,我们应该怎么做呢?


更新

感谢@Quentin,但他/她的建议也无法解决问题。 完整且最小的示例代码为:

#include <functional>
#include <iostream>

class Example 
  public:

  template<typename... Args>
  double getSome(Args... args) 
    for (auto x : args...) 
      std::cout << x << '\n';
    
  

  template<typename... Args>
  std::function<double(Args...)> getSomeFun() 
        return std::bind(&Example::getSome<Args...>, this);
  

;

int main() 
  Example e;
  e.getSomeFun<double, double, double>()(1.0, 2.0, 3.0);

错误信息是:

In file included from test2.cpp:14:0:
/usr/include/c++/7/functional: In instantiation of ‘struct std::_Bind_check_arity<double (Example::*)(double, double, double), Example*>’:
/usr/include/c++/7/functional:854:12:   required from ‘struct std::_Bind_helper<false, double (Example::*)(double, double, double), Example*>’
/usr/include/c++/7/functional:875:5:   required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = double (Example::*)(double, double, double); _BoundArgs = Example*]’
test2.cpp:29:25:   required from ‘std::function<double(Args ...)> Example::getSomeFun() [with Args = double, double, double]’
test2.cpp:36:40:   required from here
/usr/include/c++/7/functional:841:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
       static_assert(_Varargs::value
       ^~~~~~~~~~~~~
test2.cpp: In instantiation of ‘std::function<double(Args ...)> Example::getSomeFun() [with Args = double, double, double]’:
test2.cpp:36:40:   required from here
test2.cpp:29:58: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = double (Example::*)(double, double, double); _BoundArgs = Example*; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<double (Example::*(Example*))(double, double, double)>](((Example*)this))’ from ‘std::_Bind_helper<false, double (Example::*)(double, double, double), Example*>::type aka std::_Bind<double (Example::*(Example*))(double, double, double)>’ to ‘std::function<double(double, double, double) 
’
         return std::bind(&Example::getSome<Args...>, this);

【问题讨论】:

您的声明要求调用为e.getSomeFun&lt;double, double, double&gt;()(1.0, 2.0, 3.0);。你想推迟创建包直到它可以从你称之为std::function的3个doubles中推断出来吗? 你总是要立即调用getSomeFun返回的函数对象吗?如果是这样,为什么这个返回函数的中间步骤?如果不是,也许您可​​以重写您的示例,以便调用与getSomeFun 的调用不在同一个表达式中? (此外,您可能想尝试编译您发布的代码以消除拼写错误。在线编译器可能对此很有用;C++ tag info page 上有在线编译器列表。) 谢谢,我更新了代码和错误信息。 【参考方案1】:

使用绑定,您需要放置占位符参数:

std::bind(&Example::getSome<Args...>, this,
    std::placeholders::_1,
    std::placeholders::_2,
    std::placeholders::_3
);

您需要放置的占位符数量等于您的函数所需的参数数量。

我建议在这种情况下使用 lambda,因为可变参数占位符不是一个东西:

template<typename... Args>
std::function<double(Args...)> getSomeFun() 
    return [this](Args... args) 
        return getSome(args...);
    ;

此外,如果您可以在调用站点构建std::function,则可以使用推导函数返回类型来消除调用位置的std::function 开销,并且不需要std::function

template<typename... Args>
auto getSomeFun() 
    return [this](Args... args) 
        return getSome(args...);
    ;

【讨论】:

以上是关于如何返回使用参数包定义的成员函数的 std::function 对象?的主要内容,如果未能解决你的问题,请参考以下文章

请问啥是成员函数的定义?

Python函数总结大全(函数定义,参数种类返回值等)

4. 参数传递与返回值

类模板模板类函数模板模板函数

当类成员参数具有相同名称时,如何定义构造函数?

Python趣味入门9:函数是你走过的套路,详解函数调用参数及返回值