7

Below are two cases.

Case 1) Base->BaseIndirect->DerivedIndirect

Case 2) Base->Derived

In Case 2), I am able to call a template function of Base class using 3 notations. In Case 1), I am able to call template function of Base class using only 1 of those notations. And, I am NOT able to call template function of BaseIndirect using any notation :(. How do I fix this? Thanks.

struct Base {
  template<bool R> inline void fbase(int k) {};
};

template<class ZZ> struct BaseIndirect : Base {
  template<bool R> inline void fbaseIndirect(int k) {};
};


template<class ZZ>
struct DerivedIndirect : BaseIndirect<ZZ> {
  DerivedIndirect() {
    this->fbase<true>(5);         // gives error, line 13
    fbase<true>(5);               // gives error, line 14
    Base::fbase<true>(5);           // WORKS, line 15
    this->fbaseIndirect<true>(5); // gives error, line 16
    fbaseIndirect<true>(5);       // gives error, line 17
    BaseIndirect<ZZ>::fbaseIndirect<true>(5);   // gives error, line 18
  }
};

template<class ZZ>
struct Derived : Base {
  Derived() {
    this->fbase<true>(5); //  WORKS
    fbase<true>(5);       // WORKS
    Base::fbase<true>(5); // WORKS
  }
};


int main() {
  Derived<int> der;
  DerivedIndirect<int> derIndirect;
};                              

ERRORS on compilation

test.cpp: In constructor 'DerivedIndirect<ZZ>::DerivedIndirect()':
test.cpp:14: error: 'fbase' was not declared in this scope
test.cpp:17: error: 'fbaseIndirect' was not declared in this scope
test.cpp: In constructor 'DerivedIndirect<ZZ>::DerivedIndirect() [with ZZ = int]':
test.cpp:34:   instantiated from herep 
test.cpp:13: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<'
test.cpp:16: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<'
test.cpp:18: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<'
anon
  • 73
  • 1
  • 3

1 Answers1

14

The reason that many of these calls are failing is that there's a syntactic ambiguity you need to resolve using the single most obscure use of the template keyword. Instead of writing

this->fbase<true>(5);

You need to write

this->template fbase<true>(5);

The reason is that without the template keyword, the compiler parses this as

(((this->fbase) < true) > 5)

Which is nonsensical. The template keyword explicitly removes this ambiguity. Adding the template keyword into the other cases you mentioned should fix those problems.

I'm actually not sure why this works for direct base classes, so if someone could answer that part of the question I'd love to see what the answer is.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • It doesn't work for direct base classes; the only case where it worked was using the non-templated `Base` base class's name explicitly. – Jeremiah Willcock Feb 08 '11 at 05:27
  • Wow this is really "the single most obscure use of the template keyword", haha! Thanks this saved me from some problems! – B M Feb 19 '14 at 11:21
  • 1
    (Very late, but you asked:) `Base` is not a template, so the compiler can look up `Base::fbase` and see it's a template. `BaseIndirect` is dependent, there might be some specialization of `BaseIndirect` where `fbaseIndirect` is a data member instead of a templated member function, so it assumes that it's a non-templated member by default (without a `typename` or `template` to say otherwise). `BaseIndirect::fbaseIndirect(5)` would work too, as it's not dependent on `ZZ`. – Artyer Aug 21 '22 at 17:39