NickV
NickV

Reputation: 1646

Confused with simple mix of non-type templates and functions returning tuple

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

Answers (1)

Seth Carnegie
Seth Carnegie

Reputation: 75130

For the first, you can recursively build a parameter pack using structs 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 ints and use the ... to expand them like

Foo<Ints>...

which expands to

Foo<Int1>, Foo<Int2>, ...

in your function.

Upvotes: 1

Related Questions