2016-05-15 2 views
0

Учитывая пакет параметров и вектор строк, я хочу, чтобы кортеж был рекурсивно, что будет принимать по одному из каждого за раз и добавить его в кортеж. Итак, если бы у меня был вектор с «string1», «string2», «string3» и пакетом параметров 5, 2.5, true ... в результате получился бы «string1», «string2», 2.5, «string3» ", правда.Стройте кортеж рекурсивно

Вот что я пытался до сих пор

в моей основной я сделать что-то вроде этого

std::vector<std::string> string_vec; 
std::tuple<> t; 

//initalize string_vec to something 
set_up_strings(string_vec); 

//pass an empty tuple to start building with the strings and args 
tuple_maker(t, string_vec, args...); 

где мой tuple_maker рекурсивно добавляет один из каждого.

template<typename T, typename... Args, typename... Ts> 
void tuple_maker(std::tuple<Ts...> t, std::vector<std::string> &vec, T value, Args... args) 
{ 
    auto newTup1 = tuple_append(t, vec.begin()); 
    auto newtup2 = tuple_append(newTup1, value); 
    vec.erase(vec.begin()); 

//now pass in the vector and args after removing front of each 
    tuple_maker(newtup2, vec,args...); 
} 

в конце концов, когда нет больше арга, эта функция будет вызываться (окончание рекурсии)

template<typename... Ts> 
std::tuple<Ts...> tuple_maker(std::tuple<Ts...> t, std::vector<std::string> &vec) 
{ 

int tup_size = std::tuple_size<decltype(t)>::value; 
std::cout<< "final tuple has size of " << tup_size << std::endl; 

//return t; 

} 

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

для справки, вспомогательная функция «tuple_maker» Я использую здесь

template <typename NewType, typename... TupleElem> 
std::tuple<TupleElem..., NewType> tuple_append(const std::tuple<TupleElem...> &tup, const NewType &n) 
{ 
return std::tuple_cat(tup, std::make_tuple(n)); 
} 

Я пытался что-то вроде этого ...

template<typename T, typename... Args, typename... Ts, typename... ret> 
std::tuple<ret...> tuple_maker(std::tuple<Ts...> t, std::vector<std::string> &vec, T value, Args... args) 
+0

Если вы используете C++ 14, 'auto' в результате должно быть достаточным ... если бы вы не экспериментировали с объединением' auto' с '-> decltype()', где в скобках decltype вы должны передать вызов функции, которая генерирует кортеж ... –

+0

вы можете сделать функции return type auto ?, редактировать Я использовал C++ 11, но я попробую 14 – user2770808

+0

да, это должно быть принято, поскольку компилятор может вывести результат из возвращаемого утверждения ... –

ответ

0

Вы должны вернуть значение из неконечной версии из tuple_maker:

return tuple_maker(newtup2, vec, args...); 

И от последней единицы:

return t; 

Таким образом, цепочка обращений к различным инстанциациям tuple_maker превращается в цепочку хвостовых вызовов, последней возвращающийся накопленное значение.

+0

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

+0

Что вы подразумеваете под «make»? Тип возврата каждого конкретного экземпляра определяется компилятором, и когда вы хотите создать экземпляр результирующего объекта, вы можете использовать ключевое слово 'auto', если вы не хотите перечислять все пары типов строк, из которых состоит кортеж. – bipll

1

Я вижу несколько возможных проблемы в вашем tuple_maker определения (почему вы пропускание итератора tuple_append?), Но это выглядит как у вас есть ручка на то, что вы пытаетесь сделать, так что я буду позвольте вы сами разбираете это.

Ваш вопрос, кажется, спрашивает, как определить, что должно быть типа возврата для вашей функции. Есть несколько способов сделать это: .

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

Absent C++ 14 (в котором вы можете просто использовать auto в качестве возвращаемого значения), вы можете создать генератор типа для функции, как это:

#include <tuple> 
#include <type_traits> 
#include <utility> 

template <typename> 
struct RetMaker { 
    using type = std::tuple<>; 
}; 

template <typename T, typename... Rest> 
struct RetMaker<std::tuple<T, Rest...>> { 
    using rest = typename RetMaker<std::tuple<Rest...>>::type; 
    using type = decltype(std::tuple_cat(
           std::declval<std::tuple<std::string, T>>(), 
           std::declval<rest>())); 
}; 

Тогда возвращаемый тип вашей функции является typename RetMaker<std::tuple<Ts...>>::type ,

Следует отметить, что для достижения этого существует множество других способов, в том числе и без использования std::tuple_cat, но это было первое, что появилось в моей голове, что не требовало большого количества дополнительной набрав. Суть бит /std::declval: Дайте мне тип, который возникает при вызове std::tuple_cat на кортеж std::string, T, и рекурсивный результат этого применяется к остальной части кортежа.

Смежные вопросы