Search code examples
c++boostboost-tuples

C++ Cannot call base class method from within derived class


this is my first question, I hope I do everything correct.

I try to derive a class from a boost tuple. Boost's tuples provide a get() template method to access the individual fields. Interestingly I cannot use the method from within the derived class.

The following code shows the problem:

#include <iostream>
#include <boost/tuple/tuple.hpp>
using namespace std;

template<typename A>
class Derived : public boost::tuple<A>
{
public:
    Derived() : boost::tuple<A>() {}

    A& getVal0()
    {
        return get<0>();
        // does not compile:
        //error: 'get' was not declared in this scope

        return boost::tuple<A>::get<0>();
        // does not compile
        //error: expected primary-expression before ')' token

        return boost::tuples::get<0>(*this);
        //works
    }
};  

int main() {
    Derived<int> a;

    a.get<0>() = 5;

    cout << a.get<0>() << endl; 
    cout << a.getVal0() << endl; 
    return 0;
}

I wonder why I can access the get<0>() method from the main function

a.get<0>() = 5;

but not from within the A& getVal0() method:

error: 'get' was not declared in this scope

The second return line was my try to scope the method call to the base class:

return boost::tuple<A>::get<0>();

And this generates a different error

error: expected primary-expression before ')' token

Calling the external function `boost::tuples::get<0>(*this) works. And this workaround is okay to me. But I am still wondering why I cannot use the tuple method at this point.

In the boost documentation is a notice for Visual C++

Note! The member get functions are not supported with MS Visual C++ compiler. Further, the compiler has trouble with finding the non-member get functions without an explicit namespace qualifier. Hence, all get calls should be qualified as: tuples::get(a_tuple) when writing code that should compile with MSVC++ 6.0.

But I am using GCC 4.5.2 & 4.8.1

Thanks in advance


Solution

  • Assuming there is a get<I>() member function template in the base class, you probably want to use

    this->template get<0>()
    

    The this part is needed to make it a dependent look-up (you can use proper class qualification, too, but that's a bit of a pain and unnecessary unless you are hiding a base class name). The template part is necessary to tell the compiler that the dependent name (get) happens to be a template.

    The primary reason why this (or some other qualification) and template are needed is the two phase compilation model for templates:

    • Any name which doesn't immediately depend on a template argument in some form is looked up only during phase I, i.e., in the context where the template is defined. Since the template argument is unknown and, thus, the exact layout of the base class isn't known (it may be specialized) any name in a base class is ignored. Using any qualification causing the name to depend on the template argument, e.g., using this->, moves the look-up into phase II, i.e., when the template is instantiated.
    • Once a name is dependent there arises an ambiguity if an expression involves a < character while the template is parsed in phase I, i.e., when the template arguments are not, yet, known: The < can either be the start of an explicit template argument for a member function call or it can be the less-than operator. Since explicit mention of template arguments is rare (well, at least, it was rare when these rules were made), it is assumed to be the less-than operator by default. To state that the name is actually a member function template with an explicitly specified template argument, it needs to be preceded by the keyword template (pretty similar to types needing a typename).