Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't see function-template overload from recursive call

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...);
}
like image 308
Yola Avatar asked Feb 14 '26 07:02

Yola


1 Answers

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)...);   
}
like image 137
TartanLlama Avatar answered Feb 16 '26 20:02

TartanLlama



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!