0

I am learning templates in C++. So reading examples from different sources(including SO). One such example whose statement i am unable to understand(or rather i think is incorrect) is given below:

class Base {
protected:

    template <typename T1>
    void print_pi() {
        std::cout << (T1)3.141596 << std::endl;
    };

};
template <typename T2>
class Derived : public Base {
};

template <typename T3>
class DoubleDerived : public Derived<T3> {
public:
    void test() {
        print_pi<int>(); // This creates error, however changing to Base::print_pi<int>(); works.
    }
};

The user of the accepted answer says:

In the class Derived the name print_pi is a dependent name.

My question is that isn't print_pi a non-dependent name? I mean it doesn't doesn't depends on a template parameter. For instance, print_pi<T> is a dependent name but in OP's code inside the derived class DoubleDerived the name print_pi is non-dependent IMO. Can someone tell me why the user says that print_pi is a dependent name. I mean even print_pi<int> is non-dependent. I was thinking of writing an answer there saying that print_pi is a non-dependent name and according to Non-dependent name lookup members, the problem is that the compiler does not look in dependent base classes when looking up nondependent names but then some people closed the question.

Am i right in saying that the currently accepted answer is incorrect in saying that print_pi is a dependent name?

Jason
  • 36,170
  • 5
  • 26
  • 60
  • The `print_pi` function depends on which `Derived<>` you inherit from, so it is dependent. – NathanOliver Apr 06 '22 at 12:45
  • 1
    Remind that `Derived` might be specialized, so `DoubleDerived` might not inherit from `Base`. `print_pi();` IS `Derived::print_pi();` which turns to be `Base::print_pi();`. – Jarod42 Apr 06 '22 at 12:46
  • @Jarod42 So are you saying that because `print_pi();` is the same as `Base::print_pi();` so `print_pi` is non-dependent? Or are you saying the because `print_pi();` is the same as `Derived::print_pi();` so `print_pi` is dependent. Sorry if i didn't correctly interpret your last comment. – Jason Apr 06 '22 at 12:59
  • It is dependent. `DoubleDerived` doesn't know it inherits from `Base` (and with specialization, it might not inherits from `Base`). (it only inherits from `Derived`). My last sentence was to say that by "hazard", the method finally comes from non-template class, but it is irrelevant. the only **direct** base class of `DoubleDerived` is template, so access of base class member should use dependent notation (as `this->` or `Derived::` (and extra `template` because of ``)). – Jarod42 Apr 06 '22 at 13:16
  • @Jarod42 Ok so if it is dependent, then the rule *"compiler does not look in dependent base classes when looking up **nondependent** names"* does not apply to `print_pi` right? If yes, then since `print_pi` is dependent so compiler should look into the dependent base class(??) as the rule quoted above only applies to non-dependent names and it should find the inherited `print_pi`. What is happening here, can you explain as an answer if you got time. Thanks for the discussion. But comments are many times deleted on SO. – Jason Apr 06 '22 at 13:25
  • Our wording *"it is dependent"* is pedantically wrong, it should be *"it should be dependent (to compile)"* as we want `print_pi()` to refer to the one from template base class `Derived`... – Jarod42 Apr 06 '22 at 14:23

1 Answers1

1

My question is that isn't print_pi a non-dependent name?

  • As written, print_pi<int> is a non-dependent name, so according to cppreference

    For a non-dependent name used in a template definition, unqualified name lookup takes place when the template definition is examined.

    We cannot look into base class (which is template), and no (template) function print_pi exist in global scope. So the compilation error.

  • Base::print_pi<int>(); is also not dependent. qualified name takes place:

    If the lookup of the left hand side name comes up with a class/struct or union name, the name on the right hand side of :: is looked up in the scope of that class (and so may find a declaration of a member of that class or of its base), with the following exceptions [..]

    Notice that it is not yet checked that Base is really a base of the class (Demo). It would be done once the method would be instantiated (Demo)

  • this->template print_pi<int>();/Derived<T3>::template print_pi<int>(); are dependent. and so, from cppreference

    For a dependent name used in a template definition, the lookup is postponed until the template arguments are known

    So print_pi<int>() can be found in base classes (if present Demo (else error happens Demo)).

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • You said in your current answer that `print_pi` is non-dependent so the quoted statement from the [answer](https://stackoverflow.com/a/71766399/17881448) is incorrect in saying that it is dependent right? Similarly in one of your comment you also said that it is dependent. – Jason Apr 06 '22 at 14:31
  • As-is, the name is not dependent, (so would produce compile error). We want it to be a dependent-name. As (wrong) shortcut, we often said *"it is dependent"* instead of *"it should be dependent"*. It is the case in the answer too, answerer provide ways to make it dependent. – Jarod42 Apr 06 '22 at 14:57