递归地构建元组

时间:2016-05-15 18:45:08

标签: c++ templates recursion tuples variadic-templates

给定一个参数包和一个字符串向量,我想以递归方式构建一个元组,每次一个地取第一个,并将其附加到元组。所以,如果我有一个带有“string1”,“string2”,“string3”和参数包5,2.5,true的向量...结果元组将是“string1”,5,“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...);
}

最终当没有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 args之类的内容,就像我之前提到的那样,它打印出大小为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)

2 个答案:

答案 0 :(得分:1)

我可以在tuple_maker中看到几个可能出现的问题 定义(为什么要将迭代器传递给tuple_append?),但它 看起来你已经掌握了你想要做的事情,所以我会让 你自己解决了。

您的问题似乎是询问如何确定返回的内容 类型应该是您的功能。有几种方法可以做 此

一个很简单,但需要大量重复代码的,是 使用decltype使用尾随返回类型。但是,既然你的 tuple_maker函数有多行代码,很可能 最好通过另一种方法来做到这一点。

缺少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的情况下进行操作,但这是第一个突然出现在我脑海中的并不需要大量的额外打字。 decltype / std::declval位的本质是:给我在std::tuple_cat元组上调用std::string, T得到的类型,并将其递归结果应用于其余部分元组。

答案 1 :(得分:0)

您应该从tuple_maker的非最终版本返回一个值:

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

从最后一个:

return t;

这样,对tuple_maker的各种实例化的调用链变成了一个尾调用链,最后一个返回累计值。