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