[英]map of pointers to functions of different return types and signatures
我正在寻找一种通过字符串输入来调用不同函数的方法。
我有一个映射,该映射将每个唯一的字符串与一个函数指针联系在一起,并具有一个查找函数来搜索该映射并返回一个指针(如果找到)。
现在的诀窍是,我需要一种方法来存储和返回指向至少具有不同返回类型(如果可能)以及具有不同签名的函数的指针。
用法是:
从网络套接字获取字符串输入->查找并执行找到的功能->将结果直接推回套接字以进行序列化和发送,而不在乎实际发生的情况。
这可行吗? 如果没有,一个人将如何完成这项任务?
可以用一些不同的样板代码来完成。 如果签名的数量足够少,则可以容纳多个函数指针向量(每种函数类型一个),然后容纳一个映射,该映射将函数名称与类型标识符(用于选择向量)以及向量在向量中的位置进行映射。
第二种选择是存储boost::variant
(同样,如果签名集很小)。 您将需要提供一个访问者对象,该对象可以评估功能(针对存储的每种功能类型)并产生结果。 该类型由boost::variant
类型管理,因此不需要将类型标签存储在映射中。
您也可以使用完全类型擦除并将标记确定要调用的函数的类型以及boost::any
存储函数指针的对象存储在映射中。 您可以使用类型信息来检索指针并执行功能,但是必须根据功能类型手动处理switch
。
另一方面,最简单的方法是编写具有固定接口的适配器。 然后,只需将指向适配器的指针存储在映射中即可。
虽然不能存储不同的函数指针,但是可以存储包含这些函数的对象。
#include <iostream>
#include <cmath>
#include <map>
#include <string>
using namespace std;
class Functor{
public:
template<class T>
void operator()(T data){}
};
template<class T>
class BaseFunctor : public Functor{
public:
virtual void CallFunction(T data){ }
};
class FunctionPointer1 : public BaseFunctor<void *>{
public:
void doFunction1(){
cout << "Do Function 1"<<endl;
}
template<class T>
void CallFunction(T data){ doFunction1(); }
template<class T>
void operator()(T data){ this->CallFunction(data); }
};
class FunctionPointer2 : public BaseFunctor<int>{
public:
void doFunction2(int variable){ cout << "Do function 2 with integer variable" << variable <<endl; }
template<class T>
void CallFunction(T data) { doFunction2(data);}
template<class T>
void operator()(T data){ this->CallFunction(data); }
};
class FunctionPerformer{
private:
map<string,Functor> functions;
public:
FunctionPerformer(){
//init your map.
FunctionPointer1 function1;
FunctionPointer2 function2;
//-- follows
functions["Function1"] = function1;
functions["Functions2"] = function2;
//-- follows
}
Functor getFunctionFromString(string str){
return functions[str]
}
};
int main(int argc, char *argv[])
{
map<string,Functor> functions;
FunctionPerformer performer;
Functor func1, func2; // to hold return values from perfomer()
FunctionPointer1 *fn1; // to casting and execute the functions
FunctionPointer2 *fn2; // to casting and execute the functions
func1 = performer.getFunctionFromString("Function1");//get data
func2 = performer.getFunctionFromString("Function2");
//following two lines to cast the object and run the methods
fn1 = reinterpret_cast<FunctionPointer1 *>(&func1);
(*fn1)(NULL);
//following two lines to cast the object and run the methods
fn2 = reinterpret_cast<FunctionPointer2 *>(&func2);
(*fn2)(10);
system("Pause");
return 0;
}
我认为编辑部分使内容更清晰吗? 该代码可以进行一些优化。 玩吧。
不,这实际上是不可行的,如果您想执行此类操作,则需要一种真正的解释语言。 一旦签名不是恒定的,那么您需要做更多的事情。
如何使所有这些功能具有相同的签名? 您可以使所有返回类型都实现一个接口,或者使用集合,类,联合或结构。 参数相同。
您不能使用专业化和模板来解决此问题吗?
template <class T>
T FooBar(void * params);
template<> int FooBar<int>( void * params );
template<> char FooBar<char>( void * params );
可以存储适配器以消除不匹配,而不是存储彼此之间太不同而无法容纳在同一数据结构中的函数指针本身。 这是一种类型擦除的形式。 一个例子:
// Imaginary important resources
blaz_type get_blaz();
qux_type get_qux();
// The functions we'd like to put in our map
int foo(blaz_type);
std::string bar(qux_type);
using context_type = std::tuple<blaz_type, qux_type>;
using callback_type = std::function<void(context_type, socket_type&)>;
using std::get;
std::map<std::string, callback_type> callbacks = {
{
"foo"
, [](context_type context, socket_type& out)
{ marshall(out, foo(get<0>(std::move(context)))); }
}
, {
"bar"
, [](context_type context, socket_type& out)
{ marshall(out, bar(get<1>(std::move(context)))); }
}
};
在此示例中,适配器不是有状态的,因此您实际上可以将void (*)(context_type, socket_type&)
用作callback_type
。
请注意,这种设计有点脆弱,因为context_type
需要了解存储的回调可能需要的每种参数。 如果稍后需要存储需要新类型参数的回调,则需要修改context_type
-如果改进了上述设计, 不要使用像0
和1
这样的幻数作为std::get
参数为自己省去一些麻烦(特别是在从context_type
中删除类型的相反情况下)。 如果所有回调都使用相同的参数,这不是问题,在这种情况下,您可以完全省去context_type
并将这些参数直接传递给回调。
关于LWS的示范 。
这在带有可变参数模板的C ++ 11中是可行的。 在https://stackoverflow.com/a/33837343/1496826中查看我的答案
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.