Reputation: 347
Given a parameter pack and a vector of strings, I want to build a tuple recursively that will take the first of each at a time, and append that to the tuple. So If I had a vector with "string1", "string2", "string3" and a parameter pack of 5, 2.5, true... the resulting tuple would be "string1", 5, "string2", 2.5, "string3", true.
Heres what I've tried so far
in my main I do something like this
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...);
where my tuple_maker recursively adds one of each.
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...);
}
eventually when there are no more args, this function will be called(ending the recursion)
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;
}
If I pass in something like string1-3, and 3 args like I mentioned before, It prints the tuple having a size of 6 so I believe it is creating it correctly. However, I am having trouble returning it back to the main function. I dont know how to set up the return types so that it will correctly bring back the final tuple back to the previous function, and then back to the main.
for reference, the helper 'tuple_maker' function I use is here
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));
}
I tried something like this...
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)
Upvotes: 2
Views: 2495
Reputation: 3083
I can see a couple of possible problems in your tuple_maker
definition (why are you passing an iterator to tuple_append?), but it
looks like you have a handle on what you are trying to do, so I'll let
you sort that out yourself.
Your question appears to be asking how to determine what the return type should be for your function. There are a couple of ways to do this.
One, which is simple but requires a lot of duplication of code, is to use a trailing return type using decltype. However, since your tuple_maker function has more than one line of code, it is probably better to do this via another method.
Absent C++ 14 (in which you can just use auto
as the return value),
you can create a type generator for your function like this:
#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>()));
};
Then the return type of your function is typename
RetMaker<std::tuple<Ts...>>::type
.
I should note that there are many other varied ways to achieve this, including doing do without using std::tuple_cat
, but this was the first one that popped into my head that didn't require a large amount of additional typing. The essence of the decltype
/std::declval
bit is: Give me the type that results from calling std::tuple_cat
on a std::string, T
tuple and the recursive result of this applied to the rest of the tuple.
Upvotes: 1
Reputation: 11940
You should return a value from the non-final version of tuple_maker
:
return tuple_maker(newtup2, vec, args...);
And from the final one:
return t;
This way the chain of calls to various instantiations of tuple_maker
turns into a chain of tail calls, the last one returning accumulated value.
Upvotes: 0