Reputation: 1646
As exercise, I am trying to write 2 simple functions taking a non-type template int N. The first one needs to create a tuple consisting of N copies of some object of type T. I would like it to resemble the following:
template <class T, int N>
constexpr std::tuple<T...> fun(T t) {
return (N > 0) ? std::tuple_cat(t, fun<T, N-1>(t)) : std::make_tuple(t);
}
I also tried something like this unsuccessfully (http://liveworkspace.org/code/3LZ0Fe). I would like to be able to instantiate it with T = bool, say:
auto bools = fun<bool, 10> (false);
The second one should be a slight variation; I have a templated struct Foo and I would like to create a tuple containing a Foo< 0 >, ..., Foo< N >
template <int N> struct Foo {
static const int id = N;
}
template <template <int> class T, int N>
constexpr ??? fun2 (???) {...}
Since templated functions can't be partially specialized, I don't even know how to write a proper termination for my recursion. I would like to do this completely statically without using for loops.
==================================================================================
Following Seth's suggestion I was stuck with writing the fun function itself which recursed infinitely:
template<typename T, int N>
typename fun_helper<T, N>::type
fun(T t) {
if (N > 0)
return typename fun_helper<T, N>::type
{ std::tuple_cat(std::make_tuple(t), fun<T, N-1>(t)) };
else return typename fun_helper<T, N>::type { };
}
By using an additional struct with a termination, I was able to get this working:
template<typename T, int N> struct fun {
typename fun_helper<T, N>::type make(T t) {
return typename fun_helper<T, N>::type
{ std::tuple_cat(std::make_tuple(t), fun<T, N-1>().make(t)) };
}
};
template<typename T> struct fun<T, 0> {
typename fun_helper<T, 0>::type
make(T t) {
return typename fun_helper<T, 0>::type { };
}
};
The call is still relatively clumsy:
auto conds = fun<bool, 3>().make(false);
Is there a way to get it working without this additional struct ?
auto conds = fun<bool, 3>(false);
Upvotes: 3
Views: 380
Reputation: 75130
For the first, you can recursively build a parameter pack using struct
s for partial specialisation (I show you this way because it relates to #2). This code isn't tested and doesn't take care of the default value for the elements, but it gives you the idea and the default value code can be easily added.
template<typename T, int N, typename... Rest>
struct fun_helper {
typedef typename fun_helper<T, N - 1, T, Rest...>::type type;
};
template<typename T, typename... Rest>
struct fun_helper<T, 0, Rest...> {
typedef std::tuple<Rest...> type;
};
template<typename T, int N>
typename fun_helper<T, N>::type fun() {
return typename fun_helper<T, N>::type { };
}
For the second, you can combine the techniques above with a parameter pack of int
s and use the ...
to expand them like
Foo<Ints>...
which expands to
Foo<Int1>, Foo<Int2>, ...
in your function.
Upvotes: 1