我正在构建一个C ++程序,需要将字符串映射存储到函数指针。但是,每个函数可能具有不同的返回类型和参数。我试图解决这个问题的方法是创建函数,如获取一个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*
的原因是可能存在我需要返回不同类型的多个值的情况。一个例子是,如果在上面,我想要返回结果地图和地图中的条目数。不过,我还没有弄清楚如何构建那个阵列。
修改
所以基于到目前为止的反应,似乎很清楚这是解决这个问题的错误方法。考虑到这一点,任何人都可以提出更好的建议吗?我需要能够将各种函数存储在单个映射中,这意味着我需要能够为获取和返回不同类型的函数定义单个数据类型。能够返回多个值非常重要。
答案 0 :(得分:2)
对于公然将风格类型安全地投向风的想法无视我自己的恐惧,有两件事情立即浮现在脑海中。
首先,当string2map超出范围时,您认为究竟会指出什么?
其次是你不必转为无效*。 Void *在C ++中得到特殊处理,因为任何东西都可以投射到它。
如果你坚持尝试推动这个,我首先将返回类型改为void,然后将void *作为函数的输入参数。
例如:
void string2map(void* args, void* returnedMap);
这样你就必须在一个实际上拥有地图指向的范围内实例化地图。
答案 1 :(得分: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;
}
编辑:
我刚刚重读了你的问题。您可能希望查找Generalized Functors并查看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 :(得分:1)
$ 5.3.1 / 3 - “一元&amp;运算符的结果是指向它的指针 操作数。操作数应为左值或qualid 。“
$ 5.3.1 / 2 - “以下每个一元运算符的结果是a 的 prvalue 即可。“
因此,实际上你试图获取一个不允许的右值的地址。
此外,C ++不允许返回数组。
所以,你真的想开始看你想要的东西。按值返回地图而不是一个明确的选项。
答案 3 :(得分: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
答案 4 :(得分: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);
}
答案 5 :(得分:0)
@hansmaad密钥将提供有关签名的信息。有一些不同的选项,所以它将是一个带有几个条款的条件。 - ewok 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<>()
。
函数指针在插入地图时会转换为公共类型,并在调用时转换回正确的类型。