如何在 C++ 中的变量中存储任何类型的函数?

How to store any kind of function in a variable in C++?

我将如何在变量中存储具有任意数量参数的任意类型的函数? 像这样:

int add(int i, int j) {
return i + j;
}

template<typename Function, typename... Args>
class Class {
private:
    std::function<Function(Args...)> function;
public:
    Class(Function _function, Args... _args) {
        Now what?
    }
};

int main() {
    Class test(add, 1, 2);
    test.function();
}

你可以尝试类似的东西

#include <iostream>
#include <functional>
#include <tuple>

int add(int i, int j) {
    return i + j;
}

template<typename Function, typename... Args>
class Class {
private:
    Function function_;
    std::tuple<Args...> args;
public:
    Class(Function _function, Args... _args) :  
        function_ { std::forward<Function>(_function) } ,
        args{std::forward<Args>(_args)...}
    {}

    auto function()
    {
        return std::apply(function_,args);
    }
};

int main() {
    Class test(add, 1, 2);
    std::cout<< test.function() << std::endl ;
}

演示:https://wandbox.org/permlink/ZqFSSN2K5HU9HMRm

这就是 bind 的用途!

您的 Class 实际上只是 std::bind。假设您对它有进一步的用途,并让它包装 std::bind 逻辑。所以我们需要存储一个不接受进一步参数的 std::function 和 returns(在这种情况下)int…但我们将使其成为通用的(ReturnType)。

然后在初始化期间你 "bind" 你构造 Class 的参数,并将它们转发到 std::function(使用 std::forward 允许更多的移动语义复杂参数类型)。

#include <functional>
#include <iostream>

int add(int i, int j)
{
    return i + j;
}

template <typename Function, typename... Args>
class Class
{
private:
    using ReturnType = std::invoke_result_t<Function, Args...>;
    std::function<ReturnType()> function;

public:
    Class(Function _function, Args... _args) 
        : function(std::bind(_function, std::forward<Args>(_args)...))
    {}

    auto Call()
    {
        return function();
    }
};

int main() {
    Class test(add, 1, 2);
    std::cout << test.Call() << '\n';
}

// Output: 3

(live demo)

或者,如果您不需要 Class 做更多的事情,那就是:

#include <functional>
#include <iostream>

int add(int i, int j)
{
    return i + j;
}

int main()
{
    auto func = std::bind(add, 1, 2);
    std::cout << func() << '\n';
}

// Output: 3

(live demo)


引导说明

你的 std::function<Function(Args...)> 类型是错误的,因为 Function 是整个函数的类型,但你已经像 return 类型一样使用它了。

在 c++11 及更高版本中,您可以使用 Lambda closures.They 完全按照您的描述进行操作。

例如:

int a = 1; 
int b = 2;
int c = [a, b]{ return a + b; }

等于:

struct TestFunctor {
  int a;
  int b;
  TestFunctor(int a, int b):a(a), b(b){}
  int operator()(){return a+b;}
};

int a = 1; 
int b = 2;
int c = TestFunctor(a,b)();
printf("%d\n", c);

Lambda 可以转换为 std::function 并随时调用... 例如:https://wandbox.org/permlink/1RQUF3UUrsgRdJ42

template<class R>
struct Class {
  std::function<R()> function;
  template<class F, class...Args>
  Class( F&& f, Args&&...args ):
    function(
      [
        f=std::forward<F>(f),
        tup=std::make_tuple( std::forward<Args>(args)... )
      ]
      ()->R
      {
        return std::apply(f,tup);
      }
    )
  {} // ctor body
};
template<class F, class...Args>
Class( F, Args... )-> Class< std::invoke_result_t< F const&, Args const&... > >;

那里。

int main() {
  Class test(add, 1, 2);
  test.function();
}

请注意,我的 Class 类型仅取决于 return 类型。

接受的答案不好,因为 std::bind 完全可以用 lambda 代替,使用 std::bind 在现代 c++ 中是 old-fashioned 并且可能会导致一些性能问题,因为 std::function的结构有点重。

[请参阅 为什么在 C++14 中使用 std::bind 而不是 lambda? ]

先介绍一下c++20 std::bind_front,这个函数意在替代std::bind:

int add(int i, int j, int k) {
    return i + j + k;
}

auto f1 = std::bind_front(add, 1);
auto f2 = std::bind_front(add, 1, 2);
auto f3 = std::bind_front(add, 1, 2, 3);
// all will print '6'
std::cout << f1(2, 3) << '\n';
std::cout << f2(3) << '\n';
std::cout << f3() << '\n';

并且不要忘记包含 <functional> header :)