ideas
ideas copied to clipboard
`std::is_default_destructible` и друзья
Предлагается ввести следующие type traits:
namespace std {
template<class T> struct is_default_destructible;
template<class T> struct is_default_copy_constructible;
template<class T> struct is_default_move_constructible;
template<class T> struct is_default_copy_assignable;
template<class T> struct is_default_move_assignable;
} // namespace std
Эти структуры предоставляют ::value == true
тогда и только тогда, когда соответствующая функция определяется компилятором:
- явно посредством синтаксиса
= default;
- неявно при отсутствии какой-либо декларации.
is_default_XXX
— более строгое условие, чем is_XXX
, но менее строгое, чем is_trivially_XXX
.
Примеры
struct A {
int a;
};
static_assert(std::is_copy_constructible<A>::value);
static_assert(std::is_default_copy_constructible<A>::value);
static_assert(std::is_trivially_copy_constructible<A>::value);
struct B {
std::string b;
};
static_assert(std::is_copy_constructible<B>::value);
static_assert(std::is_default_copy_constructible<B>::value);
static_assert(std::is_trivially_copy_constructible<B>::value == false);
struct C {
std::string c;
C(const C& rhs) : c(rhs.c + "_copy") { }
};
static_assert(std::is_copy_constructible<C>::value);
static_assert(std::is_default_copy_constructible<C>::value == false);
static_assert(std::is_trivially_copy_constructible<C>::value == false);
struct D {
std::unique_ptr<std::string> d;
};
static_assert(std::is_copy_constructible<D>::value == false);
static_assert(std::is_default_copy_constructible<D>::value == false);
static_assert(std::is_trivially_copy_constructible<D>::value == false);
Мотивация
Наличие свойства is_default_...
говорит, что объект этого типа может быть безопасно создан/скопирован/перемещён/уничтожен применением операции к каждому из полей, при этом нет ограничений на каждое поле.
Такие type traits обобщают работу с агрегатами, в частности, их преобразование в кортежи и обратно через Boost.PFR, и преобразование в менее стандартные структуры данных (например, SoA).
На текущий момент С++ имеет type trait is_aggregate
, имеющий похожий функционал.
Однако, соответствующим ему типам позволено иметь явно определённые операторы присваивания и деструкторы:
struct Aggregate {
std::string a;
std::string b;
std::string c;
Aggregate& operator=(const Aggregate& rhs) { std::tie(a, b, c) = std::tie(c, a, b); return *this; }
Aggregate& operator=(Aggregate&& rhs) { std::tie(a, b, c) = std::tie(b, c, a); return *this; }
~Aggregate() { std::cout << "Destructor\n"; }
};
static_assert(std::is_aggregate_v<Aggregate>);
static_assert(std::is_copy_assignable<Aggregate>::value);
static_assert(std::is_default_copy_assignable<Aggregate>::value == false);
static_assert(std::is_trivially_copy_assignable<Aggregate>::value == false);
Замечания
Декларация и определение
Отметим, что для следующего кода установить истинность type trait невозможно:
// a.h
struct DontKnow {
~DontKnow();
};
static_assert(std::is_default_destructible<DontKnow>::value == false);
// a.cpp
DontKnow::~DontKnow() = default;
Короткая форма
В духе C++17 вводятся короткие формы:
namespace std {
template<class T> bool is_default_destructible_v = is_default_destructible<T>::value;
template<class T> bool is_default_copy_constructible_v = is_default_copy_constructible<T>::value;
template<class T> bool is_default_move_constructible_v = is_default_move_constructible<T>::value;
template<class T> bool is_default_copy_assignable_v = is_default_copy_assignable<T>::value;
template<class T> bool is_default_move_assignable_v = is_default_move_assignable<T>::value;
} // namespace std
Похоже, есть в Reflection TS:
template <SpecialMemberFunction T> struct is_implicitly_declared;
template <SpecialMemberFunction T> struct is_defaulted;
All specializations of these templates shall meet theUnaryTypeTrait
requirements (20.10.1). If their template parameter reflects a special member function that is implicitly declared (foris_implicitly_declared
) or that is defaulted in its first declaration (foris_defaulted
), the base characteristic of the respective template specialization istrue_type
, otherwise it isfalse_type
.