Конвертировать argv и safe в кортеж
Есть ли возможность преобразовать массив массивов произвольной длины в целые и сохранить их в кортеже?
Вот пример:
int main(int argc, const char* argv[]) {
auto input = convert(argc, argv);
}
Так что, если я назову основной:
./main 1 2
input = std::tuple<int, int>(1, 2);
а также:
./main 2
input = std::tuple<int>(2);
Я надеюсь, вы понимаете, что я ищу.
2 ответа
Динамический размер кортежа, с одним типом? То, что вы ищете, это std::vector<int>
,
Количество элементов в кортеже фиксируется во время компиляции.
Я не был удовлетворен ответами, которые вы получили на этот вопрос, поэтому я разработал решение для вас. Это не должно восприниматься как признак того, что я согласен с тем, что ваша идея хорошая:-)
Проблема при преобразовании динамических данных в статическую полиморфную функциональность заключается в том, что у вас должен быть готовый массив специализаций, готовый - по одному для каждой возможности в вашей среде выполнения. Это та же самая проблема, которая преследует идиомы двойной отправки.
Вот минимальная демонстрация программы, которая преобразует argv
в соответствующий tuple
и затем вызывает функцию шаблона (шаблонизируется на аргументах шаблона кортежа).
Я ограничил количество аргументов до 5 + название программы, но вы можете увеличить этот предел, добавив записи в массив switch_functions
,
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// this is a template of a function that does something with a tuple of strings of any size.
// it's left to the reader to figure out what to do with it.
template<class...Args>
void do_something_with_tuple(const std::tuple<Args...>& tuple)
{
std::cout << "hello! " << sizeof...(Args) << std::endl;
}
// this is a type that manufactures a tuple of <size> strings
template<size_t size>
struct make_string_tuple
{
using rest = typename make_string_tuple<size-1>::type;
using mine = std::tuple<std::string>;
using type = decltype(std::tuple_cat(std::declval<mine>(), std::declval<rest>()));
};
// this is the terminator specialisation that ends the sequence of strings in a tuple
template<>
struct make_string_tuple<0> {
using type = std::tuple<>;
};
// this is a convenience typedef that obviates the use of the typename keyword
template<size_t size>
using make_string_tuple_t = typename make_string_tuple<size>::type;
// this is a function that initialises one element of a tuple from a corresponding position in a vector
template<size_t i, size_t n>
struct init_tuple{
static void apply(make_string_tuple_t<n>& t, const std::vector<std::string>& x)
{
std::get<i>(t) = x[i];
init_tuple<i+1, n>::apply(t, x);
}
};
// this is the terminator specialisation for the above
template<size_t n>
struct init_tuple<n, n> {
static void apply(make_string_tuple_t<n>& t, const std::vector<std::string>&)
{
}
};
// a template function that manufactures a tuple of size <size>, populates it from a vector
// which must be at least as large, and then calls the template function do_something_with_tuple
template<size_t size>
void call_it(const std::vector<std::string>& x)
{
using tuple_type = make_string_tuple_t<size>;
tuple_type t;
init_tuple<0, size>::apply(t, x);
do_something_with_tuple(t);
}
// a test program
auto main(int argc, char**argv) -> int
{
// the type of function to call with a vector of arguments
using switch_function = void (*)(const std::vector<std::string>&);
// a vector of pointers to concrete versions of call_it
static const switch_function switch_functions[] = {
call_it<0>,
call_it<1>,
call_it<2>,
call_it<3>,
call_it<4>,
call_it<5>,
call_it<6>,
};
// convert argv into a vector of strings
std::vector<std::string> x;
while (argc--) {
x.emplace_back(*argv++);
}
// call the appropriate version of call_it
switch_functions[x.size()](x);
return 0;
}