Question
Can I use template parameters to refer to base class member functions?
I'm trying to understand why this code doesn't compile with GCC but compiles with MSVC:
template<class TParams>
class Selector : public TParams::DataSource1, public TParams::DataSource2
{
using DataSource1 = typename TParams::DataSource1;
using DataSource2 = typename TParams::DataSource2;
public:
template<class Fn>
static void ForEachDataSource(Fn && fn)
{
fn.template operator()<DataSource1>();
fn.template operator()<DataSource2>();
}
void Select(int i)
{
ForEachDataSource([&, this]<typename T>()
{
this->T::Query(i);
});
}
};
https://godbolt.org/z/bnv9jcYEe
The class Selector
is inherited from multiple classes which provide member function Query
. Selector::Select
then calls Query
from each of the base classes. I've decided to move iteration into a separate function so that I wouldn't need to duplicate logic for each of the base classes.
The code above fails to compile with GCC with the following error:
error: 'T' is not a class or namespace
36 | this->T::Query(i);
In my understanding T
is class DataSource1
in this context and there should be no errors.
Ok, what if we omit this->
?
ForEachDataSource([&, this]<typename T>()
{
T::Query(i);
});
In my understanding, the code is also OK because T
refers to one of the base classes, but
MSVC doesn't agree with me on this one:
error C2352: 'DataSourceF::Query': a call of a non-static member function requires an object
Explicitly casting this
to one of the base classes works in all compilers but requires some detection to support both const and non-const qualified functions.
static_cast<T *>(this)->Query(i); // What if `this` is `const`?
Note that calling Query
directly also works in all compilers regardless of used method:
this->DataSource1::Query(i);
DataSource2::Query(i);
Does the standard prohibits using template parameters to refer to base classes when calling their member functions? Which compiler is correct in this case?