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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…