вернуть массив void *

Я строю программу на C ++, которая должна хранить карту строк для указателей на функции. Однако каждая функция может иметь разные типы и параметры возврата. Я пытаюсь решить эту проблему, создав функции, которые принимают массив пустых указателей и возвращают массив пустых указателей, а затем приводят аргументы и возвращаемые значения по мере необходимости.

Чтобы понять, как это будет работать, я пытаюсь создать простой манекен, но не могу его скомпилировать. Я пробовал несколько вещей, но продолжаю получать разные ошибки. вот пример:

#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

Решение

Вы конвертируете 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’s 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);

Таким образом, вы должны будете создать свою карту в области видимости, которая на самом деле иметь карта для указания.

2

$ 5.3.1 / 3 — «Результат одинарного & оператор является указателем на его
операнд. Операнд должен быть lvalue или квалифицированный

$ 5.3.1 / 2 — «Результатом каждого из следующих унарных операторов является
prvalue

Таким образом, вы пытаетесь получить адрес значения, которое не разрешено.

Далее, C ++ не позволяет возвращать массив.

Итак, вы действительно хотите начать смотреть на то, что вы хотите. Возврат карты по значению вместо этого является одним определенным вариантом.

1

Я пытаюсь решить эту проблему, создав функции, которые принимают массив пустых указателей и возвращают массив пустых указателей, а затем приводят аргументы и возвращаемые значения по мере необходимости.

Это (действительно очень) плохо. Взгляните вместо этого на 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 Ключ даст информацию о подписи. Есть несколько различных вариантов, так что это будет условно с парой предложений. — 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 ++ будет reinterpret_cast<>(),

Указатели функций преобразуются в общий тип при вставке в карту и возвращаются к их правильному типу при вызове их.

0
По вопросам рекламы [email protected]