Код такой:
#include <iostream>
#include <type_traits>
class A
{
A() = default;
A(const A&) = default;
A(A&&) = default;
A& operator=(const A&) = default;
A& operator=(A&&) = default;
~A() = default;
int a;
};
int main()
{
std::cout << std::boolalpha <<
std::is_trivially_copy_assignable_v<A> << " " <<
std::is_trivially_copy_constructible_v<A> << " " <<
std::is_trivially_move_assignable_v<A> << " " <<
std::is_trivially_move_constructible_v<A> << " " <<
std::is_trivially_destructible_v<A> << " " <<
std::is_trivially_copyable_v<A> << "\n";
return 0;
}
И выход false false false false false true
. Но согласно cppreference:
Тривиально копируемый класс — это класс, который
- имеет по крайней мере один допустимый конструктор копирования, конструктор перемещения, оператор присваивания копирования или оператор присваивания перемещения,
- каждый подходящий конструктор копирования тривиален
- каждый подходящий конструктор перемещения тривиален
- каждый допустимый оператор присваивания копии тривиален
- каждый подходящий оператор присваивания перемещения тривиален, и
- имеет неудаляемый тривиальный деструктор.
Таким образом, из первых четырех логических выходных данных ни один из конструктора копирования, конструктора перемещения, оператора присваивания копирования и оператора присваивания перемещения не является тривиальным, поэтому он должен быть нетривиально копируемым; Однако последним выходным логическим значением является true
.
Примечание. Вы можете сделать ~A() = default
и A() = default
общедоступными, чтобы создавать объекты, но основной вопрос остается прежним.
@Sebastian Я пробовал gcc 12.2 и msvc 19.29. Стандартная версия C++20.
@ ALX23z Не могли бы вы указать, как это требование соответствует приведенному определению / стандартной формулировке?
@ Себастьян, ты попал в серую зону. Что-то, что никто никогда не удосужился проверить, потому что никто никогда не использовал это. Делая большинство конструкторов/назначений закрытыми, класс фактически непригоден для использования. Я не думаю, что авторы стандарта учитывали такие случаи, когда писали его.
из первых четырех логических выходных данных ни один из конструктора копирования, конструктора перемещения, оператора присваивания копирования и оператора присваивания перемещения не является тривиальным. Это не то, что проверяют черты is_trivially...
.
Похоже, проблема вызвана изначально неправильной формулировкой в стандарте, которая была рассмотрена в CWG 1734 , но кажется, что она все еще не реализована ни в gcc , ни в clang, а в обсуждении clang упоминаются возможные проблемы с abi в случае исправления.
@LanguageLawyer Err ... Это довольно косвенно, если ctor копирования класса тривиален, а std::is_trivially_copy_constructible_v
ложно.
Это довольно косвенно, если ctor копирования класса тривиален, а std::is_trivially_copy_constructible_v
ложно. Почему? В конце концов, это не говорит std::has_trivial_copy_constructor_v
.
Вопрос не в том, можно ли скопировать экземпляр этого класса?
std::is_trivially_copyable
ответы
если вы скопируете этот экземпляр с побайтовой копией, будет ли результат таким же, как при копировании с использованием оператора копирования?
Это связано с тем, что класс A
имеет подходящий конструктор перемещения, который является тривиальным. Более того, он также имеет тривиальный неудаляемый деструктор, и поэтому класс A
удовлетворяет всем требованиям, приведенным ниже, из тривиально копируемого класса:
Тривиально копируемый класс — это класс:
который имеет по крайней мере один допустимый конструктор копирования, конструктор перемещения, оператор присваивания копирования или оператор присваивания перемещения
где каждый допустимый конструктор копирования, конструктор перемещения, оператор присваивания копирования и присваивание перемещения оператор тривиален и
который имеет тривиальный неудаляемый деструктор (11.4.7).
(выделено мной)
Обратите внимание на акцент, по крайней мере, что означает, что класс A
удовлетворяет всем 3 вышеуказанным требованиям.
Деструктор тривиален, поскольку он не предоставляется пользователем и удовлетворяет всем трем условиям, приведенным ниже:
Деструктор тривиален, если он не предоставляется пользователем и если:
деструктор не виртуальный
все прямые базовые классы его класса имеют тривиальные деструкторы, и
для всех нестатических элементов данных своего класса, имеющих тип класса (или их массив), каждый такой class имеет тривиальный деструктор.
Точно так же конструктор перемещения также тривиален, что является одним из требований (второе, чтобы быть конкретным) для тривиально копируемого класса.
Конструктор копирования/перемещения для класса X тривиален, если он не предоставляется пользователем и если:
класс X не имеет виртуальных функций (11.7.3) и виртуальных базовых классов (11.7.2), и
конструктор, выбранный для копирования/перемещения каждого прямого подобъекта базового класса, тривиален, и
для каждого нестатического члена данных X, который имеет тип класса (или его массив), конструктор, выбранный для скопировать/переместить этот элемент тривиально;
Проблема в том, что, скажем, он сообщает, что деструктор не тривиален по признакам типа. Таким образом, некоторые из заявленных значений определенно неверны.
@ ALX23z Я думаю, вы неправильно поняли, что означают первые четыре черты.
std::is_trivially_copy_constructible_v<T>
не проверяет, есть ли у T
тривиальный конструктор копирования, на котором основан тривиально-копируемый.
Вместо этого он проверяет, является ли определение переменной формы
T t(u);
где u
— переменная типа const T
, будет правильно сформирована в контексте, не связанном с T
, и что при построении переменной будут использоваться только тривиальные функции. Это включает проверку на доступность и проверку на неудаленный доступный деструктор.
То же самое относится в аналогичной форме к другим чертам _constructible_
и _assignable_
. Эти черты не имеют прямого отношения к is_trivially_copyable
. Черта is_trivially_copyable
говорит вам, можете ли вы использовать memcpy
для копирования объектов этого типа. Он не говорит вам, будет ли копирование/перемещение-конструкция/присваивание возможным и тривиальным, для чего и нужны другие трейты.
Просто для полноты: какой компилятор и стандартную версию вы использовали?