EDIT: This is not a bug, just me not knowing about dependent name lookups in templated base classes (which MSVC "helpfully" resolves without errors).
I wrote a functor implementation a while back, and a simple "Event" wrapper that uses it. It compiles fine under MSVC, but GCC gives an error about a member variable in the base class, subscribers
, not being declared; changing subscribers
to this->subscribers
resolves the issue(!). It appears to happen only with the curiously recurring template pattern, and with partial template specialization.
Simplified source (sorry for the mind-bending template usage...):
#include <vector>
template<typename TEvent>
struct EventBase
{
protected:
std::vector<int> subscribers;
};
template<typename TArg1 = void, typename TArg2 = void>
struct Event : public EventBase<Event<TArg1, TArg2> >
{
void trigger(TArg1 arg1, TArg2 arg2) const
{
// Error on next line
auto it = subscribers.cbegin();
}
};
template<typename TArg1>
struct Event<TArg1, void> : public EventBase<Event<TArg1> >
{
void trigger(TArg1 arg1) const
{
// Using `this` fixes error(?!)
auto it = this->subscribers.cbegin();
}
};
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
int main()
{
return 0;
}
Am I invoking undefined behaviour somewhere? Is my syntax somehow wrong? Is this really a bug in GCC? Is it perhaps a known bug? Any insight would be appreciated!
More details: Compiled using g++ -std=c++11 main.cpp
. I'm using GCC version 4.7.2. Exact error message:
main.cpp: In member function ‘void Event<TArg1, TArg2>::trigger(TArg1, TArg2) const’:
main.cpp:17:15: error: ‘subscribers’ was not declared in this scope
This is a bug in MSVC instead. Names from dependent base classes have to be "thisambiguated".
The reason is that unqualified lookup of dependent names proceeds in two phases. During the first phase, the base class is not yet known and the compiler cannot resolve the name. MSVC does not implement two-phase name lookup and delays the lookup until the second phase.
The full specialization
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
does not suffer from this problem, because both the class and its base are regular classes, not class templates, and there is no template dependency to begin with.
When porting C++ code from MSVC to gcc/Clang, dependent name lookup disambiguation and the template
keyword disambiguation (i.e. calling member function template using ::template
, ->template
or .template
syntax) are two of the subtleties that you have to deal with (empty base optimization is another one). For all the Standards compliance rhetoric, this will probably never be fixed for reasons of backwards compatibility.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With