Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

You're trying to specify the return type, based on current == i ? type1 : type2 which is your issue.

The return type should be known in compile-time. In your case decltype is returning double as type, then you're trying to call .el0 method of that primitive type.

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