带有不同参数的c++ std::函数变量
C++ std::function variable with varying arguments
在我的回调系统中,我想用不同的参数存储std::function
(或其他东西)。
的例子:
- 我想呼叫
void()
- 我想呼叫
void(int, int)
我希望1)和2)存储在同一个变量中,并选择实际调用
FunctionPointer f0;
FunctionPointer f2;
f0();
f2(4, 5);
有可能这样做吗?或者我必须根据输入参数计数创建几个"functionpointer"模板。
编辑
是否可以利用std::bind来完成这个任务?使用std::bind,我可以有std::function<void()> f = std::bind(test, 2, 5);
编辑2
实际用例:我有一个触发器系统,我想给动作分配函数指针,所以当动作发生时,函数被调用。伪代码示例:
structure Trigger
{
Function f;
}
Init:
Trigger0.f = pointer to some function ()
Trigger1.f = pointer to some function (a, b)
Input:
Find Trigger by input
if (in == A) Trigger.f();
else Trigger.f(10, 20)
或者
Input:
Find Trigger by input
if (in == A) f = bind(Trigger.f);
else f = bind(Trigger.f, 10, 20);
f()
std::function<void()>
和std::function<void(int, int)>
是两种完全不同的类型。您需要某种联合功能(或多态性)来存储未知类型的对象。
如果您可以使用Boost,您可以轻松地使用boost::variant
:
// Declaration:
boost::variant<std::function<void()>, std::function<void(int, int)> > f;
// Calling, explicit:
if (fContainsNullary()) {
boost::get<std::function<void()>>(f)();
} else {
boost::get<std::function<void(int, int)>>(f)(4, 5);
}
由您来提供fContainsNullary()
的逻辑。或者,您可以通过使用访问器来使用变量自己存储的值类型知识:
struct MyVisitor : boost::static_visitor<void>
{
result_type operator() (const std::function<void()> &a) {
a();
}
result_type operator() (const std::function<void(int, int)> &a) {
a(4, 5);
}
};
// Calling, via visitor:
boost::apply_visitor(MyVisitor(), f);
如果Boost不是一个选项,你可以手工制作一个合适的union
来达到同样的目的。
下面的解决方案可能适合您(我不确定这里的代码是否绝对正确):
为std::function
创建一个带有虚拟析构函数的包装器,以启用动态强制转换
class function_wrapper_base
{
virtual ~function_wrapper_base();
}
template <class... Args>
class function_wrapper
: public function_wrapper_base
{
public:
std::function<void, Args...> f;
...
};
创建一个类variant_function_holder
class variant_function_holder
{
std::unique_ptr<function_wrapper_base> f;
...
template <class... Args>
void operator()(Args&&... args)
{
function_wrapper<std::decay<Args>::type...> * g = dynamic_cast<function_wrapper<std::decay<Args>::type...>>(f.get());
if (g == nullptr)
{
// ToDo
}
g->f(std::forward<Args>(args)...);
}
};
嗯,如果你可以使用RTTI,你可以这样定义一个MultiFuncObject
,你可以很容易地绑定其他函数。而且,你可以很容易地打电话给他们。但不幸的是,这种方法只适用于有限数量的参数。但实际上boost::bind
也支持有限数量的参数(默认为9),所以你可以扩展这个类来满足你的需要。
在给你MultiFuncObject
的源代码之前,我想告诉你如何使用它。它接受一个模板参数作为返回类型。可以使用+=
操作符绑定新函数。通过一些模板魔法,类可以区分具有相同实参计数但至少有一个不同实参类型的绑定函数。
你需要c++ 11,因为MultiFuncObject
使用std::unordered_map
和std::type_index
。
用法:
#include <iostream>
using namespace std;
void _1() {
cout << "_1" << endl;
}
void _2(char x) {
cout << "_2" << " " << x << endl;
}
void _3(int x) {
cout << "_3" << " " << x << endl;
}
void _4(double x) {
cout << "_4" << " " << x << endl;
}
void _5(int a, int b) {
cout << "_5" << " " << a << " " << b << endl;
}
void _6(char a, int b) {
cout << "_6" << " " << a << " " << b << endl;
}
void _7(int a, int b, int c) {
cout << "_7" << " " << a << " " << b << " " << c << endl;
}
int main() {
MultiFuncObject<void> funcs;
funcs += &_1;
funcs += &_2;
funcs += &_3;
funcs += &_4;
funcs += &_5;
funcs += &_6;
funcs += &_7;
funcs();
funcs('a');
funcs(56);
funcs(5.5);
funcs(2, 5);
funcs('q', 6);
funcs(1, 2, 3);
return 0;
}
我希望这是接近你想要的。以下是MultiFuncObject
的来源:
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
using namespace std;
template <typename R>
class MultiFuncObject {
unordered_map<type_index, void (*)()> m_funcs;
public:
MultiFuncObject<R> operator +=( R (* f)() ) {
m_funcs[typeid( R() )] = (void (*)()) f;
return *this;
}
template <typename A1>
MultiFuncObject<R> operator +=( R (* f)(A1) ) {
m_funcs[typeid( R(A1) )] = (void (*)()) f;
return *this;
}
template <typename A1, typename A2>
MultiFuncObject<R> operator +=( R (* f)(A1, A2) ) {
m_funcs[typeid( R(A1, A2) )] = (void (*)()) f;
return *this;
}
template <typename A1, typename A2, typename A3>
MultiFuncObject<R> operator +=( R (* f)(A1, A2, A3) ) {
m_funcs[typeid( R(A1, A2, A3) )] = (void (*)()) f;
return *this;
}
R operator()() const
{
unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R() ));
if (it != m_funcs.end()) {
R (*f)() = ( R (*)() )(it->second);
(*f)();
}
}
template <typename A1>
R operator()(A1 a1) const
{
unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1) ));
if (it != m_funcs.end()) {
R (*f)(A1) = ( R (*)(A1) )(it->second);
(*f)(a1);
}
}
template <typename A1, typename A2>
R operator()(A1 a1, A2 a2) const
{
unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1, A2) ));
if (it != m_funcs.end()) {
R (*f)(A1, A2) = ( R (*)(A1, A2) )(it->second);
(*f)(a1, a2);
}
}
template <typename A1, typename A2, typename A3>
R operator()(A1 a1, A2 a2, A3 a3) const
{
unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1, A2, A3) ));
if (it != m_funcs.end()) {
R (*f)(A1, A2, A3) = ( R (*)(A1, A2, A3) )(it->second);
(*f)(a1, a2, a3);
}
}
};
使用std::unordered_map
存储不同的函数原型,键为std::type_index
,值为void (*)()
。当需要时,使用该映射检索正确的函数。
下面是工作示例
c++ 11救急!
如果你可以将你的函数泛化为不带参数的函数对象,那么你就可以用任意lambda调用它。
#include <iostream>
using namespace std;
template <class F>
void call_it(F&& f)
{
f();
}
int main()
{
int x = 50, y = 75;
call_it([] () { cout << "Hello!n"; });
call_it([x,y] () { cout << x << " + " << y << " = " << x + y << 'n';});
return 0;
}
如果您不需要std::function
,您可以创建一个代理类。
class fn_t {
public:
typedef void (*fn_1_t)();
typedef void (*fn_2_t)(int, int);
fn_1_t fn_1;
fn_2_t fn_2;
fn_t operator=(fn_1_t func_1) { fn_1 = func_1; return *this; }
fn_t operator=(fn_2_t func_2) { fn_2 = func_2; return *this; }
void operator()() { (*fn_1)(); }
void operator()(int a, int b) { (*fn_2)(a, b); }
};
#include <iostream>
using namespace std;
void first() {
cout << "first" << endl;
}
void second(int a, int b) {
cout << "second " << a << " : " << b << endl;
}
int main() {
fn_t f;
f = &first;
f = &second;
f();
f(5, 4);
return 0;
}
类fn_t
可以自动处理你想要的两个原型,自动分配需要的一个原型,并且可以通过给()
操作符重载适当的参数来调用两个原型的函数。
你可能想检查函数指针fn_1
和fn_2
的有效性,但我没有包括这个最小性检查。
这样做的好处是你只需要c++,甚至不需要STL和Boost。
其他答案都很好,但我也想展示我的解决方案。
这是一个小的头文件,你可以用它"拉长"函数签名。这允许您这样做(从github示例中提取):
int foo_1p(int a);
int foo_2p(int a, int b);
int foo_3p(int a, int b, int c);
int foo_4p(int a, int b, int c, int d);
int foo_5p(int a, int b, int c, int d, int e);
int foo_6p(int a, int b, int c, int d, int e, int f);
int foo_7p(int a, int b, int c, int d, int e, int f, std::string g);
...
int main()
{
std::unordered_map<std::string, std::function<int(int, int, int, int, int, int, std::string)>> map;
map["foo_1p"] = ex::bind(foo_1p, ph, ph, ph, ph, ph, ph);
map["foo_2p"] = ex::bind(foo_2p, ph, ph, ph, ph, ph);
map["foo_3p"] = ex::bind(foo_3p, ph, ph, ph, ph);
map["foo_4p"] = ex::bind(foo_4p, ph, ph, ph);
map["foo_5p"] = ex::bind(foo_5p, ph, ph);
map["foo_6p"] = ex::bind(foo_6p, ph);
map["foo_7p"] = foo_7p;
for (const auto& f : map)
{
std::cout << f.first << " = " << f.second(1, 1, 1, 1, 1, 1, "101") << std::endl;
}
}
- 使用std::函数映射对象方法
- 可组合的lambda/std::函数与std::可选
- 当使用透明的std函数对象时,我们还需要写空的尖括号吗
- std::函数常量正确性未遵循
- 具有变量Number of Arguments的std::函数的矢量
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 如何将类 1 的 std::函数绑定到类 2 的函数?
- 如何制作可以接受任何类型的参数的 std::函数和 lambda
- 如何将 STL 队列推送函数绑定到 std::函数?
- std::函数不起作用,但普通的旧函数指针可以 - 为什么?
- 获取 std::函数以推断按引用传递/按值传递
- std::bind 和 std::函数术语不值为接受 0 个参数?
- 从其存储的回调中删除 std::函数是否安全
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 创建一个带有 lambda 的 std::函数,而不知道函数的参数
- std::函数的解释
- 在调用过程中删除 std::函数