I'm trying to recursivly traverse my templated structure.
To do this, I write recursive function get_my. It returns i-th element of chained my_pair's.
get_my may be element Type, or pair type.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
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
};
///
/// ERROR occurs here!
///
template<typename PairT>
auto get_my(PairT p, int i, int current = 0) -> decltype( current == i ? p.el0 : p.el1 ){
if (current == i){
return p.el0;
} else {
return get_my(p.el1, i, current++);
}
}
template<typename T0, typename T1>
my_pair<T0, T1> make_my_pair(T0 el0, T1 el1){
return my_pair<T0, T1>(el0, el1);
}
int main()
{
my_pair<double, double> p1(12.789, 12.66);
//auto p1 = make_my_pair(12.46, 12.66);
//auto p2 = make_my_pair(p1, 12.66);
auto el = get_my(p1, 0);
cout<< el;
return 0;
}
So... the compilers says:
main.cpp:19:18: error: request for member 'el0' in 'p', which is of non-class type 'double'
return p.el0;
^
main.cpp:21:42: error: request for member 'el1' in 'p', which is of non-class type 'double'
return get_my(p.el1, i, current++);
And I really don't understand why. It seems it try to traverse farther then it should.
Even when the compiler knows that the else
block won't be entered, the code inside it must be syntactically valid. Consider what happens here when p
is double
:
if (current == i){
return p.el0;
} else {
return get_my(p.el1, i, current++);
}
get_my
gets instantiated and inside it the compiler sees return p.e10
with Pair
being double
.
The solution is overloading. Write another overload of my_get
that stops the recursion when Pair
is deduced for something else than my_pair
. This can be done with enable_if
idiom for example.
Even better, you could have an overload with my_pair<T1, T2>
that recurses, and another general template that does not. No enable_if
needed.