0

I have a functor with a templated member function. I get compilation errors when calling that member function from a second generation derived templated class. Please, take a look at the sample code given bellow that illustrates this issue. There are two #elif cases that I cannot understand why they fail. Could someone please explain?

// Tested in Coliru:
// g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp 

#include <iostream>
#include <iomanip>

// Functor allows for partial specialization of template function in class
class Functor
{
protected:    
    enum class Enum { A, B };

    template <Enum ee> bool operator() (int ii) const
    {
        if constexpr (ee == Enum::A)
            return ii % 2 == 0;
        else
            return ii % 1 == 0;
    }
};

// This is a dummy templated base class that exposes the issue that I don't understand
template <typename>
class Base : public Functor
{
public:
    using base = Functor;
    virtual ~Base () = default;

    virtual bool operator() (int ii) const
    {
        return base::operator() < Enum::B > (ii); // Compiles fine
    }
};

// This second generation derived class has quirks when accessing the member member Functor::operator()  
// The template tag does not serve any purpose besides the fact that this issue only happens with templated classe
template <typename Tag>
class Derived : public Base<Tag> // All different cases in the data member function bool Derived<Tag>::operator () compile if Base<double> is used instead of Base<Tag> 
{
public:
    using base = Base<Tag>;

    virtual bool operator() (int ii) const override
    {
#define COMPILES
#if defined(COMPILES)
        return Functor::operator() <base::base::Enum::A> (ii); // Notice that Functor::operator() is protected and is visible here becouse it's a derived class
#elif defined (DOES_NOT_ONE)
        return Base<Tag>::Functor::operator() <base::base::Enum::A> (ii); // Why doesn't this compile?
#elif defined (DOES_NOT_TWO)
        return Base<Tag>::base::operator() <base::base::Enum::A> (ii); // Why doesn't this compile?
#else
        return base::base::operator() <base::base::Enum::A> (ii); // Why doesn't this compile?
#endif
    }
};

template <typename Tag>
class DerivedNoIssue : public  Base<double> // The issue seems to be only when Base is not specialized.
{
public:
    using base = Base<double>;

    virtual bool operator() (int ii) const override
    {
        return base::base::operator() <base::base::Enum::A> (ii); // Compiles fine
    }
};

int main ()
{
    std::cout << std::boolalpha << Derived<double> () (21) << std::endl;
    std::cout << Derived<double> () (256) << std::endl;
    
    std::cout << DerivedNoIssue<double> () (256) << std::endl;

    return 0;
}
Mat
  • 202,337
  • 40
  • 393
  • 406
Catriel
  • 461
  • 3
  • 11
  • 1
    @user17732522: How did C++20 change that? – Nicol Bolas Oct 24 '22 at 17:23
  • https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords – n. m. could be an AI Oct 24 '22 at 17:25
  • 1
    @NicolBolas Ehm, right. It didn't change. For some reason I thought the C++20 change for the `<` disambiguation applied, but clearly not, since the name is not unqualified. – user17732522 Oct 24 '22 at 17:27
  • 1
    My previous comment corrected: You need to replace `::operator()` with `::template operator()` in the non-working cases, because the name is nested in a dependent base and the compiler needs to know that the `<` following is the beginning of a template argument list (instead of the less-than operator) without being able to inspect the dependent base at the point of the template definition to see whether `operator()` really is a template. See linked duplicate. – user17732522 Oct 24 '22 at 17:30
  • To make things worse, the Visual Studio compiler supports the incorrect syntax. Or is this a case of interpreting the standard? – Catriel Oct 24 '22 at 18:51
  • Visual Studio is known to not trying to follow the standard at times. When in doubt, use /std=c++latest. – n. m. could be an AI Oct 25 '22 at 05:06

0 Answers0