Почему в объявлении класса (неполного типа) нельзя использовать "is_base_of"?
Я полностью понимаю, почему эта не может работать:
class Base {};
class A;
static_assert(std::is_base_of<Base, A>::value, "");
Потому что нет никакой информации об иерархии классов, но...
Почему не может работать следующее?
class Base {};
class A : public Base {
static_assert(std::is_base_of<Base, A>::value, "");
};
(produce: an undefined class is not allowed as an argument to compiler intrinsic type trait)
Тип "A" по-прежнему не завершен в строке с static_assert (согласно определению этого понятия). Однако - компилятор уже знает "иерархию классов" и может предоставить ответ для этого.
Конечно - этот static_assert может быть перемещен в деструктор или что-то еще, чтобы исправить эту проблему, но бывают ситуации, когда это невозможно сделать, например:
class Base {};
template<typename T>
struct type_of {
static_assert(std::is_base_of<Base, T>::value, "T is not derived from Base");
using type = int; //* Some normal type in real use
};
class A : public Base {
public:
type_of<A>::type foo(); // Will not compile
};
Если это не разрешено?
Ответы
Ответ 1
Определение класса завершено (то есть, класс считается определенным) после замыкающей скобки }
.
В вашем случае, когда вы пытаетесь использовать A
с std::is_base_of
, A
еще не определено полностью:
class A : public Base {
// no closing brace for A yet, thus A isn't fully defined here
static_assert(std::is_base_of<Base, A>::value, "");
};
С другой стороны, std::is_base_of
требует типов, которые полностью определены для работы.
Таким образом, ошибка.
В качестве обходного пути вы можете поместить утверждение в деструктор A
:
class A : public Base {
~A() {
static_assert(std::is_base_of<Base, A>::value, "");
}
};
Фактически, тип класса считается полностью определенным в его телах функций-членов.
Подробнее см. здесь для более подробной информации (акцент мой):
Класс рассматривается как полностью определенный тип объекта ([basic.types]) (или полный тип) при закрытии} спецификатора класса. В классе-член класса класс считается полным в телах функций, аргументах по умолчанию, спецификаторах noexcept и инициализаторах по умолчанию (включая такие вещи во вложенных классах). В противном случае он считается неполным в пределах своей спецификации класса.
Ответ 2
Страница doc для std::is_base_of
дает:
Если оба Base и Derived являются типами неединичных классов, и они не являются тот же тип (игнорируя cv-квалификацию), Производный должен быть полным тип; в противном случае поведение undefined.
Определение для класса завершено после закрытия его области с помощью }
. Таким образом, в вашем случае генерируется ошибка.
Обратите внимание, что static assertion может отображаться в области пространства или пространства имен/файлов. Таким образом, вы можете переместить его за пределы тела класса или, если вы не хотите иметь его в своем заголовке, перейдите к файлу реализации.