Should the Variadic template options always be the last?

Should I always add variation template parameters at the end of my template parameters?

template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);

For example, I get all kinds of errors with this:

#include <functional>
#include <iostream>
#include <string>
#include <tuple>
using namespace std;

template <typename... Tp, size_t begin = 0U>
enable_if_t<begin == sizeof...(Tp), void> foo(tuple<Tp...>& t){
    cout << endl;
}

template <typename... Tp, size_t begin = 0U>
enable_if_t<begin < sizeof...(Tp), void> foo(tuple<Tp...>& t) {
    cout << get<begin>(t) << ' ';
    foo<Tp..., begin + 1>(t);
}

int main() {
    tuple<int, string, float> t = make_tuple(42, "Jonathan Mee", 13.13);

    foo(t);
}

When launched on gcc 5.1 , it gives me:

prog.cpp: when creating std::enable_if_t<(begin < sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&) [with Tp = {int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, float}; unsigned int begin = 0u; std::enable_if_t<(begin < sizeof... (Tp)), void> = void]:
prog.cpp: 21: 7: required from here
prog.cpp: 15: 23: error: there is no corresponding function to call foo(std::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, float>&)
foo<Tp..., begin + 1>(t);

prog.cpp: 8: 43: note: candidate: template<class ... Tp, unsigned int begin> std::enable_if_t<(begin == sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&)
enable_if_t<begin == sizeof...(Tp), void> foo(tuple<Tp...>& t){

prog.cpp: 8: 43: note: failed to subtract / replace the template argument:
prog.cpp: 13: 42: note: candidate: template<class ... Tp, unsigned int begin> std::enable_if_t<(begin < sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&)
enable_if_t<begin < sizeof...(Tp), void> foo(tuple<Tp...>& t) {

prog.cpp: 13: 42: note: error in the output of the template / replacement argument:

When the arguments change to:

template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);

The program works correctly: http://ideone.com/SozUbb

, , - ?

+2
3

- , .

, begin 0. , begin std::size_t .

gcc 5.1:

template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin == sizeof...(Tp), void> {
  std::cout << '\n';
}

template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin < sizeof...(Tp), void> {
  std::cout << '\n';
}

( , , , ).

, .

, . , - for_each_arg:

template<class F, class...Args>
void for_each_arg(F&& f, Args&&...args) {
  using discard=int[];
  (void)discard{((
    f(std::forward<Args>(args))
  ),void(),0)...,0};
}

std::apply, :

namespace details {
  template<class F, class Tuple, std::size_t...Is>
  decltype(auto) apply( std::index_sequence<Is...>, F&& f, Tuple&& args )
  {
    return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(args))... );
  }
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& tuple) {
  using dTuple = std::decay_t<Tuple>;
  return details::apply(
    std::make_index_sequence<std::tuple_size<dTuple>::value>{},
    std::forward<F>(f),
    std::forward<Tuple>(tuple)
  );
}

template<class F, class Tuple>
decltype(auto) for_each_tuple_element( F&& f, Tuple&& tuple ) {
  return apply(
    [&](auto&&...args){
      for_each_arg( std::forward<F>(f), decltype(args)(args)... );
    },
    std::forward<Tuple>(tuple)
  );
}

, .

template <class Tuple>
void foo(Tuple&& tuple) {
  for_each_tuple_element(
    [](auto&& arg){ std::cout << decltype(arg)(arg); },
    std::forward<Tuple>(tuple)
  );
  std::cout << '\n';
}

.

+3

. :

template <typename... Tp, size_t begin = 0U>
void foo(tuple<Tp...> t);

:

foo<Tp..., begin + 1>(t);

, . , , .

, begin , :

template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);

:

foo<begin + 1>(t);
+7

§14.1/11 [temp.param]:

- , . , - .

, , . , :

template <typename... Tp, size_t begin = 0U>
                  ^^^^^^
void foo(tuple<Tp...> t);

... Tp.

+1

All Articles