2012-12-10 153 views
2

我正在构建一个C++程序,需要存储一个字符串映射到函数指针。但是,每个函数可能有不同的返回类型和参数。我试图解决这个问题的方法是通过创建函数来获取void指针数组并返回一个void指针数组,然后根据需要转换参数并返回值。返回一个void数组*

为了弄清楚这将如何工作,我试图建立一个简单的虚拟,但不能让它编译。我已经尝试了很多东西,但是我不断收到不同的错误。这里有一个例子:

#include <string> 
#include <iostream> 
#include <map> 

using namespace std; 

void** string2map(void** args){ 
    //takes a string of the form "key:value;key:value;..." and returns a map<string,string> 
    string st = *((string**) args)[0]; 
    map<string, string> result = map <string, string>(); 
    //code doesnt matter 
    return (void*) &((void*) &result); 
} 

int main(){ 
    string test = "hello:there;how:are you?"; 
    map<string, string> result = *(map<string, string>**)string2map((void*) &((void*) &test))[0]; 

    return 0; 
} 

,当我尝试编译,我得到:

void.cpp: In function 'void** string2map(void**)': 
void.cpp:12:34: error: lvalue required as unary '&' operand 
void.cpp: In function 'int main()': 
void.cpp:17:89: error: lvalue required as unary '&' operand 

显然,有很多事情错在这里,但我真的不知道从哪里开始。任何人都可以告诉我上面的代码有什么问题,或者给我一个替代方法,我目前正在做它?

注意

的原因,我回国的void**而不只是void*是,有可能是一个情况,我需要返回多个不同类型的值。例如,如果我想要返回结果地图和地图中条目的数量。尽管如此,我还没有弄清楚如何构建这个数组。

编辑

因此,基于响应,到目前为止,它似乎很清楚,这是解决这个问题的错误的方式。考虑到这一点,任何人都可以提出更好的建议吗?我需要能够将各种功能存储在单个映射中,这意味着我需要能够为接受和返回不同类型的函数定义单个数据类型。能够返回多个值是非常重要的。

+2

你写这个的方式,无论你做什么都会出错,因为你要返回一个非静态局部变量的地址。 –

+0

此外,请考虑标记代码中与您的错误消息中指示的行相匹配的行。一目了然确定哪些线路是12和17并不容易。 –

+0

你真的只需要一个'void *'参数。如果你需要更多的东西,你总是可以让这个参数成为一个向量或一个结构体。 –

回答

2

您正在将map<string,string>转换为void**,将其返回并将其转换回map<string,string。为什么不只是返回一个map<string,string>?它也被称为string2map,这意味着你只会用一个字符串来调用它(通过你传递一个字符串的事实来备份,这个字符串被转换成一个void**然后直接转换回来)。除非你有一个很好的理由转换和void**所有的地方这可能是你需要的东西:

#include <string> 
#include <iostream> 
#include <map> 

using namespace std; 

map<string, string> string2map(string st){ 
    map<string, string> result = map <string, string>(); 
    //code doesnt matter 
    return result; 
} 

int main(){ 
    string test = "hello:there;how:are you?"; 
    map<string, string> result = string2map(test); 
    return 0; 
} 

编辑:

我刚才重读你的问题。您可能想查找广义函数,并查看Boost的std::function作为解决此问题的可能方案。这是可能通过一个包装类来改变一个函数的返回类型,像这样:

template< class T > 
class ReturnVoid 
{ 
public: 
    ReturnVoid(T (*functor)()) : m_functor(functor) {} 

    void operator() { Result = functor(); } 

private: 
    T (*m_functor)(); 
    T Result; 
}; 

// Specialise for void since you can't have a member of type 'void' 
template<> 
ReturnVoid<void> 
{ 
public: 
    ReturnVoid(T (*functor)()) : m_functor(functor) {} 

    void operator() { functor(); } 

private: 
    T (*m_functor)(); 
}; 

以此为包装可以帮助你存储与在同一阵列中不同的返回类型仿函数。

2

忽略了我自己对公然向风中投入类型安全的想法感到恐惧,有两件事情立刻就会浮现出来。

首先,当string2map超出范围时,您认为什么时候会指向什么?

其次是你不必施放void *。 void *在C++中得到了特殊的处理,因为任何东西都可以投射到它上面。

如果你坚持试图推动这个,我会开始通过改变返回类型为void,然后将void *作为输入参数传递给你的函数。

例如:

void string2map(void* args, void* returnedMap); 

这样,你就必须实例化地图的范围内将实际地图指向。

1

$ 5.3.1/3 - “一元&操作的结果是一个指针,指向其操作数 操作数须为左值或qualifiedid。”

$ 5.3。1/2 - “以下每个一元运算符的结果是 prvalue。”

所以,实际上你正在尝试取一个不允许的右值的地址。另外,C++不允许返回数组。

所以,你真的想开始看你想要什么。通过值返回地图,而不是一个确定的选项。

0

我试图解决这个问题的方法是通过创建函数来获取void指针数组并返回一个void指针数组,然后根据需要转换参数和返回值。

这真的很糟糕。看看std :: function和std :: bind,它们应该以一种优雅的方式覆盖函数签名和绑定参数之间的差异。

我返回一个void **而不仅仅是void *的原因是可能有一个情况,我需要返回不同类型的多个值。

然后返回一个包含值的对象。对于泛型,看看std :: tuple或boost :: any。

下面是一些代码:

void function1(int, const char); // defined elsewhere 
std::tuple<int,int> function2(std::string&); // defined elsewhere 

std::map<std::string,std::function<void(void)>> functionmap; 
functionmap.insert(std::make_pair("function1", std::bind(&function1, 2, 'c'))); 

std::tuple<int,int> result; 
functionmap.insert(std::make_pair("function2", [&result] { 
    result = function2("this is a test"); }); 

// call function1 
functionmap["function1"](); 

// call function2 
functionmap["function2"](); // result will now contain the result 
          // of calling function2 
0

这就是你试图这样做?

int Foo(int a) { return a; } 
typedef int (*FooFunc)(int); 

void Bar(){} 

typedef std::map<std::string, void*> FunctionMap; 
// you should use boost::any or something similar instead of void* here 

FunctionMap CreateFunctionMap(const std::string& args) 
{ 
    FunctionMap result; 
    result["Foo"] = &Foo; 
    result["Bar"] = &Bar; 
    return result; 
} 

void Call(FunctionMap::const_reference functionInfo) 
{ 
    // @hansmaad The key will give information on the signatures. 
    // there are a few distinct options, so it will be a conditional 
    // with a couple of clauses. 
    if (functionInfo.first == "Foo") 
    { 
     auto f = static_cast<FooFunc>(functionInfo.second); 
     std::cout << f(42); 
    } 
    else if (functionInfo.first == "Bar") 
    { 
     /* */ 
    } 
} 

int main() 
{ 
    auto functions = CreateFunctionMap("..."); 
    std::for_each(begin(functions), end(functions), Call); 
} 
0

@hansmaad关键会给签名信息。有几个不同的选项,所以它将是一个有条件的几个子句。 - 伊渥克33分钟前

在这种情况下,典型的解决方案是这样的:

typedef void (*func_ptr)(); 
std::map<std::string, func_ptr> func_map; 

map<string,string> string2map(string arg){ 
    //takes a string of the form "key:value;key:value;..." and returns a map<string,string> 
    map<string, string> result = map <string, string>(); 
    //... 
    return result; 
} 

// ... 

// Add function to the map 
func_map["map<string,string>(string)" = (func_ptr)string2map; 

// Call function in the map 
std::map<std::string, func_ptr>::iterator it = ... 
if (it->first == "map<string,string>(string)") 
{ 
    map<string,string> (*func)(string) = (map<string,string>(*)(string))it->second; 
    map<string,string> result = func("key1;value1;key2;value2"); 
} 

为了简便起见,我用C-风格转换的函数指针。正确的C++强制转换为reinterpret_cast<>()

函数指针在插入映射时转换为通用类型,并在调用时将其转换回正确的类型。