Я настраиваю консольную команду, которая принимает переменное количество аргументов, каждый из которых может быть базовыми типами (int, float, bool, string), а затем передаю их в функцию, которая имеет 8 перегрузок для поддержки различного количества аргументов разных типов. Как бы я проанализировал строку командной строки в значения, основанные на их типе, а затем передать их в функцию?
Я могу получить каждый аргумент через функцию const char* GetArg(int index)
, Преобразование char*
для правильного типа не проблема, так что не беспокойтесь об этой части. Хранение значений и как-то передача функции шаблона — это часть, на которой я застрял.
Например, если команда была выполнена со следующей строкой: «command 66 true 5» string value «0.56»
Затем он будет разбит на следующие аргументы и как-то сохранен:
int arg1 = GetArg(1); // 66
bool arg2 = GetArg(2); // true
int arg3 = GetArg(3); // 5
char* arg4 = GetArg(4); // "string value"float arg5 = GetArg(5); // 0.56
А затем, основываясь на количестве аргументов, вызовите правильную функцию шаблона:
// The function definition looks something like this:
void SomeFunc();
template<typename T1>
void SomeFunc(const T1& arg1);
template<typename T1, typename T2>
void SomeFunc(const T1& arg1, const T2& arg2);
// etc...
// And then somehow it would be called. This is just an example. I don't
// know how to call it in a way that would work with variable number and
// type of args.
switch (argCount)
{
case 0:
SomeFunc();
break;
case 1:
SomeFunc(arg1);
break;
case 2:
SomeFunc(arg1, arg2);
break;
case 3:
SomeFunc(arg1, arg2, arg3);
break;
case 4:
SomeFunc(arg1, arg2, arg3, arg4);
break;
case 5:
SomeFunc(arg1, arg2, arg3, arg4, arg5);
break;
}
Как бы вы сделали это возможным? Сохранение аргументов некоторым способом, который может быть передан в функцию шаблона, чтобы он знал, что тип каждого аргумента не представляется возможным, но я чувствую, что просто не думаю о чем-то.
Я не могу изменить этот интерфейс. Это сторонняя функция, с которой мне просто нужно иметь дело. Таким образом, независимо от того, как это реализовано, в конечном итоге это должно пройти SomeFunc()
,
ВАЖНО: я делаю это в Visual Studio 2012, поэтому я довольно ограничен в новых функциях C ++. Это может сделать немного C ++ 11, но это все. Пытаюсь обновить проект до более новой версии, но сейчас это то, с чем мне приходится иметь дело.
using basic_type = std::variant<int, float, bool, std::string>;
using flat_arguments = std::vector<basic_type>;
template<std::size_t...Ns>
using packed_arguments = std::variant< std::array<basic_type, Ns>... >;
template<class T, std::size_t...Ns>
std::array<T, sizeof...(Ns)> pack_one( std::vector<T> n, std::index_sequence<Ns...> ) {
return {{ std::move(n[Ns])... }};
}
template<class T, std::size_t...Ns>
std::optional<std::variant< std::array<T, Ns>... >>
pack_all(std::vector<T> n, std::index_sequence<Ns...> ) {
std::optional<std::variant< std::array<T, Ns>... >> retval;
if (n.size() >= sizeof...(Ns)) { return retval; }
(
(
(n.size()==Ns)?
void(retval.emplace( pack_one( std::move(n), std::make_index_sequence<Ns>{} ):
void()
),...
);
return retval;
}
flat_arguments get_arguments( int argc, char const* const*argv); // write this
auto invoke_somefunc = [](auto&&...args){
return SomeFunc( decltype(args)(args)... );
};
int main(int argc, char const*const* argv) {
auto args = get_arguments(argc, argv);
auto args_packed = pack_all(std::move(args), std::make_index_sequence<9>{} );
if (!args_packed) return -1;
std::visit( [](auto&& args){
std::apply( [](auto&&...args){
std::visit( invoke_somefunc, args... );
}, args );
}, args_packed );
}
это должно сделать это. Вероятно, содержит опечатки. C ++ 17.
boost
имеет эквивалентные типы (variant
а также optional
) это может заменить std
используйте выше, с некоторыми изменениями.
Расширение пакета сгиба может быть заменено взломом расширения в массиве в C ++ 11 или больше
Других решений пока нет …