Reputation: 383
I am trying to port a code that should work and compile on both Linux (GCC/C++) and windows (MSVC) however the following line is giving me trouble
template <class TDerived>
struct Event
{
inline static std::string eventId = typeid(TDerived).name();
};
struct Derived : public Event<Derived>
{
Derived() = default;
};
The code uses typeid
and name()
to set the event name,
In GNU/C++ it compiles properly in both Linux and Apple (Clang), and even in Windows using MingW. but in windows using MSVC it gives the following error
error C2027: use of undefined type 'Derived'
message : see declaration of 'Derived'
message : see reference to class template instantiation 'Event<Derived>' being compiled
basically because Derived
is incomplete at this time and is not visible in the Event
scope.
But why does GNU/GCC, MingW and Clang succesfuly compiled it? Do we have a workaround in MSVC (Visual Studio)?
Upvotes: 4
Views: 184
Reputation: 383
I found a work around and it works.
template <class TDerived>
struct Event
{
private:
static std::string getEventId() { return typeid(TDerived).name(); }
public:
inline static std::string eventId = getEventId();
};
Upvotes: 0
Reputation: 238401
C++ standard says:
[expr.typeid]
When typeid is applied to a type-id ... If the type of the type-id is a class type or a reference to a class type, the class shall be completely-defined.
As far as I can tell, the class isn't completely-defined in that context. If that interpretation is correct, then the rule is violated and the program is ill-formed. That said, I'm not 100% sure since template instantiation makes the rules quite complex.
But why does GNU/GCC, MingW and Clang succesfuly compiled it?
For whatever reason, their implementation can apparently cope with non-completely defined classes. They aren't required to successfully compile it. Technically they do not conform to the standard if they do not provide a diagnostic message (assuming the the interpretation of program being ill-formed is correct).
Do we have a workaround in MSVC (Visual Studio)?
Defining a non-inline static member seems to work in godbolt:
template <class TDerived>
struct Event
{
static std::string eventId;
};
template <class TDerived>
std::string Event<TDerived>::eventId = typeid(TDerived).name();
Note that the name is implementation defined and is not going to be the same across all language implementations.
Upvotes: 3