Question

Consider the following code:

http://coliru.stacked-crooked.com/a/def9fc0daddcca9f

#include <iostream>
#include <type_traits>

using namespace std;

struct A{
  char* ka;
};

struct B{
  char* baa;
};

template<typename T0, typename T1>
struct my_pair{
    my_pair(T0 el0, T1 el1): el0(el0), el1(el1) {}
    T0 el0;
    T1 el1; // may be next pair
};

template<typename T, int i, int current = 0>
auto constexpr get_my(const T& t, typename std::enable_if< i==current >::type* = 0) -> decltype(t.el0)
{
    return t.el0;
}

template<typename T, int i, int current = 0>
auto constexpr get_my(const T& t, typename std::enable_if< i!=current >::type* = 0) ->
    decltype( get_my<T, i, current+1>(t.el1) )
{
    return get_my<T, i, current+1>(t.el1);
}


int main()
{
    my_pair<int, my_pair<B,double>> p1(12.789, {B(), 3.14} );

    auto el1 = get_my<decltype(p1), 1>(p1);
    int t =1;
}

Here, I try to get n-th element of "array" (something like variadic sequence from boost fusion).
When I compile it, compiler says:

error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting 'template<class T, int i, int current> constexpr decltype (get_my<T, i, (current + 1)>(t.el1)) get_my(const T&, typename std::enable_if<(i != current)>::type*) [with T = my_pair<int, my_pair<B, double> >; int i = 1; int current = 900]'
     decltype( get_my<T, i, current+1>(t.el1) )

Why it not calls overloaded get_my, when i==current?

Was it helpful?

Solution

template<typename T, int i, int current = 0>
auto constexpr get_my(const T& t, typename std::enable_if< i!=current >::type* = 0) ->
  decltype( get_my<T, i, current+1>(t.el1) )
{
  return get_my<T, i, current+1>(t.el1);
}

calls the nested get_my function with wrong arguments. The type for the nested call should be get_my<decltype(t.el1), i, current+1>(t.el1) instead of get_my<T, i, current+1>(t.el1).

So the correct code should be:

template<typename T, int i, int current = 0>
auto constexpr get_my(const T& t, typename std::enable_if< i!=current >::type* = 0) ->
  decltype( get_my<decltype(t.el1), i, current+1>(t.el1) )
{
  return get_my<decltype(t.el1), i, current+1>(t.el1);
}

OTHER TIPS

Place deduced template arguments last. If you also need default arguments you sometimes want to specify, consider a different overload with forwarding.

template<int i, typename T>
auto constexpr get_my // implementation with current=0
template<int i, int current, typename T>
auto constexpr get_my

and stop mentioning them explicitly, and your code gets simpler and your bug goes away.

(you used the wrong type explictly)

live example

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top