2015-02-26 3 views
1

Предполагая следующую иерархию классов:Force ошибка компиляции на отсутствие статической переменной-члена в производных классах

//file base.h 
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 

Каждый класс в этой иерархии должны иметь свои собственные static const tChar* const iid, которые могут быть использованы для идентификации объекта без инстанцировании его. В IEvenMoreDerived эта информация отсутствует.

Теперь, где-то в коде, у меня есть шаблон функции, где осуществляется доступ к IID:

//file main.cpp 
#include "base.h" 

template<typename T> 
void queryIID() 
{ 
    std::cout << T::IID << std::endl; 
} 

int main(int argc, char* argv[]) 
{ 
    queryIID<IBase>();    //prints "iid.base" 
    queryIID<IDerived>();   //prints "iid.derived" 
    queryIID<IEvenMoreDerived>(); //probably prints "iid.derived" 
    return 0; 
} 

Мое намерение состоит в том, чтобы получить ошибку во время компиляции при использовании queryIID<IEvenMoreDerived>(); в IEvenMoreDerived не имеет статический член iid. Я предполагаю, что это возможно, используя шаблон шаблона шаблона внутри шаблона queryIID(), но все, что я пробовал, не решило проблему.

Некоторые дополнительные пункты:

  • Использование constexpr char* вместо static const char* const, к сожалению, кажется, не представляется возможным в соответствии с The MS VS2015 Feature Preview даже в VS2015 это не будет поддерживаться.
  • После некоторого рытья я наткнулся на C++ Templates FAQ. В соответствии с этим, скрытие элемента является «функцией» шаблонов классов. Я просто не мог понять, как я могу использовать это, чтобы решить мою проблему. Кроме того, я не хочу, чтобы иерархия классов, представленная выше, была изменена на класс.
  • Среди других вопросов я нашел this somewhat similar question on SO, но это не полностью соответствовало моей проблеме.
+0

Похоже, что решение ищет проблему для меня. Если ваши IID необходимы и вы их не определяете, компилятор и/или компоновщик рано или поздно пропустят их. В лучшем случае вы замените подлинную ошибку компилятора/компоновщика с ошибкой ошибок шаблона über. –

+0

Может ли 'typeid' помочь здесь? – sharptooth

+0

Вы не можете идентифицировать OBJECT без создания экземпляра, по определению объектом является создание класса CLASS. – Rugruth

ответ

1

В качестве обходного пути, вы можете делегировать Id во внешней структуре, что-то вроде:

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

// instead of `const char* const IBase::IID = "IBase";` 
// you have to use the following 
template <> const char* const IdName<IBase>::IID = "IBase"; 
// Same for IDerived 
template <> const char* const IdName<IDerived>::IID = "IDerived"; 

И вы получили ссылки ошибку при попытке использовать IdName<IEvenMoreDerived>::IID.

Live example