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

时间:2019-07-15 10:31:58

标签: c++ variadic-templates

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

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();
}

5 个答案:

答案 0 :(得分:5)

您可以尝试类似的事情

#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

答案 1 :(得分:3)

这就是bind的目的!

您的Class实际上就是std::bind。假设您有进一步的用途,并使其包裹了std::bind逻辑。因此,我们需要存储一个std::function,该参数不接受任何其他参数,并返回(在这种情况下)int…,但我们将其设为通用(ReturnType)。

然后,在初始化期间,您将与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


Bootnote

您的std::function<Function(Args...)>类型是错误的,因为Function是整个函数的类型,但是您将其用作返回类型。

答案 2 :(得分:1)

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类型仅取决于返回类型。

答案 3 :(得分:0)

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

例如:

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

答案 4 :(得分:0)

可接受的答案不好,因为std::bind可以完全用lambda代替,因为使用std::bind是现代c ++中的老式方法,并且由于std::function的构造而导致的性能问题有点沉重。

[ see Why use std::bind over lambdas in C++14? ]

让我介绍一下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>标头:)