#include <TypeManip.h>
class A {
};
class B : public A {
};
template <class T>
class C {
char check[SUPERSUBCLASS(A, T)];
};
int main(int argc, char* argv[])
{
C<B> good;
C<int> bad;
return 0;
}
PS в vc6 выдается варнинг "nonstandard extension used : zero-sized array" вместо ошибки
ГА>Я тогда не очень понял что значит "вызывать ее в каждом конструкторе", ведь конструктор один. Или речь идет уже о производных классах от C?
Число конструкторов не ограничено (то есть, потенциально может быть создано неограниченное число конструкторов класса и в каждый из них надо не забыть поместить вызов Check(), поскольку будет существовать столько путей создания объекта сколько конструкторов было объявлено (явно или не явно)), а деструктор всего один. Вот мы и использует этот факт и именно в деструкторе размещаем код проверки. Помимо этого, компилятор, инстанцируя шаблон, генерирует только необходимые методы (если, конечно, не указано явное инстанцирование), но так как стандарт гарантирует обязательный вызов деструктора объекта перед его уничтожением, то код деструктора будет генерироваться всегда, что нам и нужно для гарантии проверки требований.
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Число конструкторов не ограничено (то есть, потенциально может быть создано неограниченное число конструкторов класса и в каждый из них надо не забыть поместить вызов Check(), поскольку будет существовать столько путей создания объекта сколько конструкторов было объявлено (явно или не явно)), а деструктор всего один. Вот мы и использует этот факт и именно в деструкторе размещаем код проверки. Помимо этого, компилятор, инстанцируя шаблон, генерирует только необходимые методы (если, конечно, не указано явное инстанцирование), но так как стандарт гарантирует обязательный вызов деструктора объекта перед его уничтожением, то код деструктора будет генерироваться всегда, что нам и нужно для гарантии проверки требований.
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>Здравствуйте, Анатолий Широков, Вы писали:
АШ>деструктор всего один. Вот мы и использует этот факт и именно в деструкторе размещаем код проверки
ДН>Интересно, а что будет если объект аллокирован на куче, а вызвыть delete для него пользователь забыл? Проверки не будет?
По-моему, undefined behavior по
3.8
4. A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which object occupied is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
тут смысл не в том что это ill-formed или нет, понятно что это баг. Но, проблема в том, что одна ошибка программиста — забыл вызвать delete, повлечет еще одну, возможно более серьезную проблему — проверка на то, что шаблон параметризирован наследником от ... не будет выполнятся.
Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>тут смысл не в том что это ill-formed или нет, понятно что это баг. Но, проблема в том, что одна ошибка программиста — забыл вызвать delete, повлечет еще одну, возможно более серьезную проблему — проверка на то, что шаблон параметризирован наследником от ... не будет выполнятся.
Почему? Проверка будет идти на этапе компиляции, когда дело дойдет до деструктора, который будет обязательно: либо самописный либо генеренный.
А уж вызывается этот деструктор где-нибудь или нет, имхо, дело десятое и на проверку не влияет.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, WFrag, Вы писали:
WF>enum { is_T_derived_from_A = boost::is_base_and_derived< A, T >::value }; WF>BOOST_STATIC_ASSERT( is_T_derived_from_A );
К>А чтобы не тащить весь boost, -- подсмотрите, как там это сделано и оставьте себе.
Здравствуйте, UgN, Вы писали:
UgN>Здравствуйте, Дмитрий Наумов, Вы писали:
ДН>тут смысл не в том что это ill-formed или нет, понятно что это баг. Но, проблема в том, что одна ошибка программиста — забыл вызвать delete, повлечет еще одну, возможно более серьезную проблему — проверка на то, что шаблон параметризирован наследником от ... не будет выполнятся.
UgN>Почему? Проверка будет идти на этапе компиляции, когда дело дойдет до деструктора, который будет обязательно: либо самописный либо генеренный. UgN>А уж вызывается этот деструктор где-нибудь или нет, имхо, дело десятое и на проверку не влияет.
Эксперимент показывает, что VC7 не инстанцирует деструктор, если он не вызывается.
Здравствуйте, Голощапов Александр, Вы писали:
ГА>Привет ALL!
ГА>допустим есть такая ситуация:
ГА>
ГА>class A {
ГА>//...
ГА>};
ГА>class B : public A {
ГА>//...
ГА>};
ГА>template<class T> class C {
ГА>//...
ГА>}
ГА>
ГА>Каким образом можно ограничить использование класса C, чтобы в качестве аргумента шаблона T можно было использовать только наследников A ?
ГА>С уважением
template<class Potomok, class Predok>
class isDerived
{
private:
//Определение не требуетсяstatic char discriminator(...);
static double discriminator(Predok*);
static Potomok* d;
public:
enum { value = ( sizeof(discriminator(d)) != sizeof(char) ) };
};
#define IS_DERIVED(Potomok, Predok) isDerived< Potomok, Predok >::value
//Ваш случай.template<class T> class C
{
private:
#ifdef _DEBUG
char blocker[IS_DERIVED(T, A)];
#endif
};
Всё считается на этапе компиляции. Правда работает только для public-наследования.