#новичкам
Трейты(или свойства объектов) - мощнейший инструмент проверки требований для исполнения кода. Вы явно в апи через sfinae или концепты можете задавать ограничения на множество типов, с которыми хотите работать, производя проверку в compile-time.
Сегодня обсудим для самой простой структуры, какими свойствами классов она удовлетворяет. Чисто, чтобы вкатиться в базовые стандартные трейты.
Проверить свойства типа можно довольно просто. static_assert + использование самого трейта:
struct A {
int a;
int b;
int c;
};
// --- true ---
static_assert(std::is_class_v<A>, "A is a class");
static_assert(std::is_aggregate_v<A>, "A is aggregate");
static_assert(std::is_standard_layout_v<A>, "A is standard-layout");
static_assert(std::is_trivially_copyable_v<A>, "A is trivially copyable");
static_assert(std::is_trivially_destructible_v<A>, "A trivially destructible");
static_assert(std::is_trivially_copy_constructible_v<A>, "A trivial copy ctor");
static_assert(std::is_trivially_move_constructible_v<A>, "A trivial move ctor");
static_assert(std::is_trivially_copy_assignable_v<A>, "A trivial copy assign");
static_assert(std::is_trivially_move_assignable_v<A>, "A trivial move assign");
static_assert(std::is_default_constructible_v<A>, "A default constructible");
static_assert(std::is_trivially_default_constructible_v<A>, "A trivial default ctor");
static_assert(std::is_object_v<A>, "A is object");
static_assert(std::is_compound_v<A>, "A is compound");
// --- false ---
static_assert(!std::is_empty_v<A>, "A is NOT empty (has members)");
static_assert(!std::is_polymorphic_v<A>, "A is NOT polymorphic");
static_assert(!std::is_fundamental_v<A>, "A is NOT fundamental");
static_assert(!std::is_scalar_v<A>, "A is NOT scalar");Вообще эти трейты - это некая шаблонные структуры. У них есть статический constexpr член value, который обращается в true, если свойство присутствует у типа, и в false если нет.
Для каждого трейта определен вспомогательный шаблон переменной с суффиктом
_v, который хранит непосредственно булево значение.Ну и по порядку:
✅ is_class.
A действительно является полноценным классом с точки зрения С++. Структуры и классы в этом смысле не отличаются.✅ is_aggregate. С агрегатами можно использовать инициализацию членов через список инициализации внутри {}.
✅ is_standard_layout. Очень упрощая, ваш класс не имеет виртуальных функций, все поля также являются standard_layout с одинаковым модификатором доступа и у него нет базовых классов.
✅ is_trivially_copyable. Класс имеет хотя бы один копирующий или перемещающий специальный метод и все они сгенерированы компилятором.
✅ is_trivially_destructible, is_trivially_copy_constructible,is_trivially_move_constructible, is_trivially_copy_assignable, is_trivially_move_assignable_v - соответствующий специальный метод должен быть сгенерирован компилятором.
Есть также версия без trivially, которая просто проверяет наличие операции в классе.
✅ is_trivially_default_constructible - дефолтный конструктор сгенерен компилятором и внутри него не выполняется никакой код(все поля типа должны иметь тривиальный дефолтный контруктор, то есть состоять только из тривиальных типов).
✅ is_object - Все, что не ссылка, не функция и не
void, то объект. Интересно, что A - это и класс, и объект. Вот такое ООП в плюсах, которые мы заслужили.✅ is_compound - указатели, ссылки, массивы, функции, классы и объединения, перечисления, и их cv-квалификации.
Дальше пойдут трейты, которым не удовлетворяет простая структура:
🙈 is_empty - имеет хотя бы одно нестатическое поле.
🙈 is_polymorphic - есть хотя бы одна виртуальная функция
🙈 is_fundamental_v - арифметические типы, void и
std::nullptr_t.🙈 is_scalar - все, что можно представить числом. Числа, указатели, перечисления.
В следующем посте можем обсудить, как ситуация изменится, если чуть подкрутить начальную структуру.
Know your traits. Stay cool.
#template #cppcore