#include <iostream>

class IBase
{
public:
    virtual ~IBase() = default;

    //a static member identifying IBase (e.g. "iid.base")
    static const char* const IID;  //initialize in implementation file
//[...]
};//class IBase

class IDerived : public IBase
{
public:
    virtual ~IDerived() = default;

    //a static member identifying IDerived (e.g. "iid.derived")
    static const char* const IID;  //initialize in implementation file
//[...]
};//class IDerived

class IEvenMoreDerived : public IDerived
{
public:
    virtual ~IEvenMoreDerived() = default;

    //missing static const member IID!
//[...]
};//class IEvenMoreDerived

const char* const IBase::IID = "IBase";
const char* const IDerived::IID = "IDerived";

template <typename T>
struct IdName
{
    static const char* const IID;
};

template <> const char* const IdName<IBase>::IID = "IBase";
template <> const char* const IdName<IDerived>::IID = "IDerived";

template<typename T>
void queryIID()
{
    std::cout << T::IID << std::endl; // IEvenMoreDerived::IID is resolved as IDerived::IID
    std::cout << IdName<T>::IID << std::endl; // link error for IEvenMoreDerived::IID.
}

int main()
{
    queryIID<IBase>();
    queryIID<IDerived>();
    queryIID<IEvenMoreDerived>();
}
