2

The following code causes my compiler to produce two errors: type name is not allowed and expected an expression.

#include <iostream>

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.
    }
};

int main() {

    DoubleDerived<float> dd;
    dd.test();
}

The issue is the line print_pi<int>() in the test() function of the DoubleDerived class. However, if this is changed to Base::print_pi<int>() everything compiles without error. What is going on here and is changing to the Base function call the only way around this issue? Additionally, why doesn't this happen if the test() function were to be in the Derived class?

Edit: The associated answer listed above still causes errors on some compilers (NVCC) so I cannot endorse that question as an actual substitute.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Hufh294
  • 89
  • 5
  • 1
    I managed to create an even smaller example that demonstrates the issue: https://godbolt.org/z/do1cT74h1. It has something to do with the fact that Derived is templated (the problems disappears without it). MSVC actually accepts this code, but gcc and clang do not. Don't know why. – wohlstad Apr 06 '22 at 11:50
  • Funny enough, MSVC is giving me the errors in the question. – Hufh294 Apr 06 '22 at 11:53
  • Strange. In addition to godbolt I am using MSVC 15.4.5 (VS2017) and your sample compiles and runs as is. – wohlstad Apr 06 '22 at 11:54
  • My apologies, I was actually using NVCC. However, MSVC 16.11.3 (VS 2019) still gives an error, however this time it is `'print_pi': identifier not found`. – Hufh294 Apr 06 '22 at 12:00
  • 2
    This is discussed in the C++ Super-FAQ: https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members . And another solution is `this->print_pi();` – aschepler Apr 06 '22 at 12:12
  • I'm finding that `this->` works on MSVC, but not on NVCC. – Hufh294 Apr 06 '22 at 12:14

2 Answers2

1

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

You can use for example

template <typename T3>
class DoubleDerived : public Derived<T3> {
public:
    void test() {
        Derived<T3>::template print_pi<int>();
    }
};

or

template <typename T3>
class DoubleDerived : public Derived<T3> {
public:
    void test() {
        DoubleDerived::template print_pi<int>();
    }
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • You said that `print_pi` is a dependent name which is incorrect because `print_pi` is non dependent. Refer to [here](https://stackoverflow.com/a/71768462/17881448). – Jason Apr 06 '22 at 15:01
0

I think that may be because you now have a print_pi() in Base, and another one in Derived class. The compiler has difficulty determining which function you want to use.

As you use template function as a class member function, that function cannot be virtual. Can a class member function template be virtual?

Personally I'd suggest to remove the base class, and write print_p1 as a template function.

Edit1: godbolt.org/z/rWzjrvT69 Here is the code that illustrates that we can use the base function in derived class.

Joe_Bao
  • 116
  • 6
  • 1
    Actuall `print_pi` is defined in `Base` only. Also you can see this minimal example that show a similar issue: https://godbolt.org/z/do1cT74h1 – wohlstad Apr 06 '22 at 11:58
  • Yes, I read your code, and I found that replacing ppp2 with Derived::ppp2 it will generate the correct result. But your case is different from the original problem. If you write the base class as a non-template class with template function, then you will find that you can use the base function ppp2 in the derived class. https://godbolt.org/z/rWzjrvT69 Here is the case – Joe_Bao Apr 06 '22 at 12:07