我将如何在变量中存储具有任意数量参数的任何类型的函数? 像这样:
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();
}
答案 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 ;
}
答案 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
或者,如果您不需要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
您的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>
标头:)