3

The question is, why it doesn't work if tuple is not at the first position of its parent. Looks like it doesn't see overload for tuple from inside _after_print.

_print(make_tuple(), 0);

Evaluates to this:

a tuple
not a tuple

And

_print(0, make_tuple());

Gives this:

not a tuple
not a tuple

template <typename _First, typename ..._Vals>
void _print(_First&& first, _Vals... _vals)
{
    cout << "not a tuple" << endl;
    _after_print(_vals...);
}

template <typename ..._List, typename ..._Vals>
void _print(tuple<_List...>&& t, _Vals... _vals)
{
    cout << "a tuple" << endl;
    _after_print(_vals...);
}

void _print() {}

template <typename ..._Vals>
void _after_print(_Vals... _vals)
{
    _print(_vals...);
}
Wandering Fool
  • 2,170
  • 3
  • 18
  • 48
Yola
  • 18,496
  • 11
  • 65
  • 106
  • 2
    TartanLlama fixed it silently, but you shouldn't use identifiers beginning with an underscore in the global scope, they are reserved. – Quentin Aug 10 '15 at 13:39

1 Answers1

1

Your issue is here:

template <typename ..._List, typename ..._Vals>
void _print(tuple<_List...>&& t, _Vals... _vals)
//                         ^^

I assume that you wanted to use perfect forwarding, but that unconditionally names an rvalue reference; reference collapsing rules do not apply there. The dead-simple fix is to declare it as const tuple<_List...>& instead, but if you want to use perfect forwarding, you'll need to do something like this:

//trait to check if a type is a std::tuple instantiation
template <typename T>
struct is_tuple : std::false_type{};

template <typename... Ts>
struct is_tuple<std::tuple<Ts...>> : std::true_type{};

//base case
void printImpl(char) {}

//forward declaration
template <typename First, typename ...Vals>
void printImpl(char,First&& first, Vals&&... vals);

//enabled when the first is a tuple
template <typename Tuple, typename ...Vals, 
          typename std::enable_if<is_tuple<typename std::decay<Tuple>::type>::value>::type* = nullptr>
void printImpl(int, Tuple&& t, Vals&&... vals)
{
    cout << "a tuple" << endl;
    printImpl(0,std::forward<Vals>(vals)...);
}

//first is not a tuple
template <typename First, typename ...Vals>
void printImpl(char,First&& first, Vals&&... vals)
{
    cout << "not a tuple" << endl;
    printImpl(0,std::forward<Vals>(vals)...);
}

//helper to fill in the disambiguating argument
template <typename... Ts>
void print(Ts&&... ts)
{
    printImpl(0,std::forward<Ts>(ts)...);   
}
TartanLlama
  • 63,752
  • 13
  • 157
  • 193