curiousJorgeXX
curiousJorgeXX

Reputation: 383

calling typeid on template difference between GNU C++ and MSVC problem

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

Answers (2)

curiousJorgeXX
curiousJorgeXX

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

eerorika
eerorika

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

Related Questions