Страницы

Поиск по вопросам

вторник, 9 июля 2019 г.

Ассерт для CRTP

Использую CRTP. В коде это выглядит так:
template class Base{ //... }; class Derived : public Base{ //... };
Начали появляться copy/paste ошибки:
class Foo : public Base{ //... }; class Bar : public Base{ //Ой //... };
Решил написать ассерт, который бы это дело проверял.
Придумал такой вариант:
template class Base{ protected: typedef T TemplateType; typedef Base BaseType; //... }; class Derived : public Base{ public: Derived(){ Q_ASSERT(typeid(*this) == typeid(Base::TemplateType)); } //... };
Но какой-то он неказистый. Работает на этапе выполнения, требует наличия каких-то непонятных тайпдефов.
И вот я здесь. Как написать такой ассерт используя C++03 и Qt? И чтобы его при этом было не стыдно людям показать.


Ответ

Такой вариант:
template class IsDerivedFrom { class No {}; class Yes { No no[2]; }; static Yes Test(B*); static No Test(...); public: enum { Is = sizeof(Test(static_cast(0)))==sizeof(Yes) }; };
template class Base { };
class D1: public Base { public: D1(){ cout << IsDerivedFrom >::Is << endl; } };
class D2: public Base { public: D2() { cout << IsDerivedFrom >::Is << endl; } };
int main() { D1 d1; D2 d2; }
Ну, понятно, что можно использовать IsDerivedFrom >::Is прямо во время компиляции.
Условие C++03 выполнено - Open Watcom успешно справился с компиляцией.
Update Решение 2. Не даст скомпилировать наследника от другого Base<>, copy-paste отработает - имени текущего класса в нем нет :). Увы, один typedef все же потребовался.
template class Base { typedef T base; };
template class IsDerivedFromBase { static void Constraints(T*p) { Base*b = p; } public: IsDerivedFromBase() { void(*p)(T*) = Constraints; } };
class D1: public Base { public: D1(){ IsDerivedFromBaseid; } };
class D2: public Base { public: D2() { IsDerivedFromBaseid; } };
int main() { D1 d1; D2 d2; }
Update 2 Пробуйте теперь:
template class IsSame { public: enum { value = 0 }; };
template class IsSame { public: enum { value = 1 }; };
template class Base { typedef T base; };
template class IsDerivedFromBaseThis { static void Constraints(T*p) { Base*b = p; } public: template IsDerivedFromBaseThis(U*) { int x[IsSame::value]; void(*p)(T*) = Constraints; } };
class D1: public Base { public: D1(){ IsDerivedFromBaseThisid(this); } };
class D2: public Base { public: D2() { IsDerivedFromBaseThisid(this); } };
int main() { D1 d1; D2 d2; }

Комментариев нет:

Отправить комментарий