2

Is there any way to reference member variables of base class templates without base class names and scope resolution operator?

template<typename D>
struct B0 {
    int value;
};
struct D0: B0<D0> {
    D0() {
        B0<D0>::value = 1; // OK.
        value = 1;         // OK without `B0<D0>::`.
    }
};

template<typename T>
struct B1 {
    T value;
};
template<typename T>
struct D1: B1<T> {
    D1() {
        B1<T>::value = 1; // OK.
        // value = 1; // Compile error without `B1<T>::`.
                      // Compile error: use of undeclared identifier 'value'
                      // `B1<T>::` is tedious everywhere `value` is referenced.
    }
};

template<typename T, typename D>
struct B2 {
    T value;
};
template<typename T>
struct D2: B2<T, D2<T>> { // CRTP
    D2() {
        B2<T, D2<T>>::value = 1; // OK.
        // value = 1; // Compile error without `B2<T, D2<T>>::`.
                      // Compile error: use of undeclared identifier 'value'
                      // `B2<T, D2<T>>::` is more tedious for CRTP.
    }
};

int main() {
    return 0;
}

Is it possible to not write B1<T>:: or B2<T, D2<T>>:: which is tedious everywhere value is referenced?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
chaosink
  • 1,329
  • 13
  • 27

1 Answers1

6

As the solutions, you have to make the name value dependent to make it visible for name lookup. Besides the one you've showed, you can also:

  1. Use using to introduce the name,

    template<typename T>
    struct D1: B1<T> {
        using B1<T>::value;   // or move it in method's scope according to your intent
        D1() {
            value = 1;        // OK.
        }
    };
    
  2. Qualify with this->.

    template<typename T>
    struct D1: B1<T> {
        D1() {
            this->value = 1;  // OK.
        }
    };
    
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • IIRC, we had to make a number of changes to our code base when Visual C++'s template handling became more standard conformant a couple of years ago. Before that, VC++ would accept references to `value` without `this->`. Do you know what the motivation was in the standard to require prefixing with `this->` which seems so obviously redundant? Why are the lookup rules for inherited members different from non-templates? The base class definition is all there... – Peter - Reinstate Monica Jun 01 '20 at 08:40
  • @Peter-ReinstateMonica The standard says that nondependent names are not looked up in dependent base classes. I think the motivation is that, template base class might be specialized; then until instantiation, the compiler can't know whether the data member exists in the base or not. Then we have to make the name dependent, which will be looked up only at the time of instantiation, and at that time the exact base specialization that must be explored will be known. – songyuanyao Jun 01 '20 at 08:45
  • Thanks for the quick reply. I know that it's usually futile to speculate about motives, but: How does adding `this->` change anything regarding unknown base class specializations? Of course it may show the coder's intent, in effect saying "I'm pretty sure that member will be there", the same way a cast shows intent. – Peter - Reinstate Monica Jun 01 '20 at 09:06
  • @Peter-ReinstateMonica Because adding `this->` making it explicit that the name is data member of the class, which depends on the template parameter, then the name has to be looked up at the time of instantiation. Otherwise, the name might be other things like global variable; even without qualification it should be found and works fine. The compiler just complains at the 1st time, it won't tries at the time of instantiation again, it might be too complex. – songyuanyao Jun 01 '20 at 09:22