0

I would like to implement static polymorphism using CRTP and also add additional types to the templates parameters.

Providing the following scenario, how can I directly access Base members from a Derived class? Is it possible without specifying the full type of the Base class?

#include <iostream>

template<class Derived, class X>
struct Base
{
    void set_a( int a ) { _a = a; }
    protected:
        int _a;
};

template<class X>
struct Derived: public Base<Derived<X>, X>
{
    int get_a( )
    {
        // return Base<Derived<X>,X>::_a; // This works!
        return _a; // error: use of undeclared identifier '_a'
    }
};

struct foo;

int main()
{
    Derived<foo> test;

    auto base_p = static_cast< Base<Derived<foo>, foo>* >( &test );
    base_p->set_a( 42 );

    int a = test.get_a();
    std::cout << a << std::endl;
}

g++5.3.1 / clang++3.8.0 output:

error: use of undeclared identifier '_a'
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Albert
  • 169
  • 2
  • 7

2 Answers2

1

You can add a using declaration in your class:

template<class X>
struct Derived: public Base<Derived<X>, X> {

  using Base<Derived<X>, X>::_a;

  /* ... */

};

You still have to specify it once though.

Holt
  • 36,600
  • 7
  • 92
  • 139
  • Nice workaround! But i would like to understand why I have to specify it once! – Albert Jul 13 '16 at 12:30
  • 1
    @Albert You have to specify it because your base class is dependent on a template parameter of your class. – Holt Jul 13 '16 at 12:33
  • Ok. Now @Holt found the real problem, I've found a related question: http://stackoverflow.com/questions/1239908/why-doesnt-a-derived-template-class-have-access-to-a-base-template-class-ident – Albert Jul 13 '16 at 14:09
1

In Derived scope, _a is not declared but inherited, so you have to write this->_a to look up in a base class or explicitly write Base<Derived<X>, X>::_a. The latter can be imported with

using Base<Derived<X>, X>::_a;

in the definition of Derived.

tl;dr

If this->_a is written, this is automatically up-cast to Base<Derived<X>, X>* to match the intrinsic operator->.

If only _a is written, an unqualified name lookup is performed. An unqualified name lookup is scope-based, which is unrelated to inheritance. In your example, the _a is in Derived::get_a, so _a is searched in

  • Derived::get_a
  • Derived
  • (File scope)

No _a is found, which triggers a compile error.

jdh8
  • 3,030
  • 1
  • 21
  • 18