FINAL UPDATE
После очень проницательного замечания @SebastianRedl я понял, что цель настоящего стандарта является для обозначения всей конструкции объекта, а не только операции внутри конструктора. Это означало бы, что в Visual C++ есть ошибка. Тем не менее, по-прежнему я считаю, что формулировка стандарта недостаточно ясна, поэтому я оставлю остальную часть своего ответа неизменной для потомков.
Чтобы уточнить: Поведение, упомянутое ОП, на самом деле является ошибкой, и в свете этого большинство из того, что я говорю ниже этого обновления, неверно.
End Update
Это на самом деле не ошибка компилятора, а странная причуда стандарта, так что ваша путаница понятно.
В соответствии со стандартом C++ 11, для is_trivially_constructible::value
должно быть true
.
§20.9
is_constructible<T,Args...>::value
верно и определение переменной для is_constructible
, как определено ниже, как известно, не называть никаких операций, которые не тривиальна
Итак, is_trivially_constructible
верно до тех пор, данный тип является конструктивным с заданными аргументами и не вызывает никаких нетривиальных операций. Ваш пример включает только один такой конструктор, конструктор копирования. Фактически, по определению «нетривиальная операция» (по существу, нетривиальный оператор или конструктор) это выполняется для вашего типа. Поэтому возвращается true
.
Однако есть одна очень странная точка! + 11 стандарта C говорит следующее о копировальных конструкторах:
§12.8.12 (курсив мой)
копировать/перемещать конструктором для класса X является тривиальным, если он не предоставленным пользователем и если
- класс X не имеет виртуальные функции (10.3) и не виртуальных базовых классов (10.1), и
- Конструктор выбран для копирования/перемещения друг прямые базовые CLAS s подобъект является тривиальным, и
для каждого нестатического элемента данных X, относящегося к типу класса (или его массиву), конструктор, выбранный для копирования/перемещения этого элемента, является тривиальным;
В противном случае конструктор копирования/перемещения не является тривиальным.
Поскольку вы действительно обеспечивают определенный пользователем конструктор копирования ваш класс не является тривиальным скопировать конструктивны. Созданный вами конструктор копирования не является тривиальным. Тем не менее, нетривиальный конструктор копирования делает для выполнения необходимых критериев для is_trivially_constructible
, чтобы вернуть true
с аргументом, который соответствует вашему конструктору копии.
На мой взгляд, это похоже на «ошибку» в стандарте. is_trivially_constructible
возвращает, является ли тип тривиально конструктивным при определенных аргументах. Это, похоже, не гарантирует, что сам конструктор считается тривиальным!
Update:
После попытки разработать тест, чтобы показать этот следующий случай, я нашел ошибку в VC11. Логика, описанная стандартом, означает, что если B
используется как под-объект (член или основание) другого типа, любой конструктор этого типа, который вызывает конструктор копирования B
, должен считаться нетривиальным по std::is_trivially_constructible
. Это не относится к VC11.
Пример кода
#include <iostream>
#include <type_traits>
struct B
{
B() {}
B(B&) {
std::cout << "not trivial\n";
}
};
struct A : B
{
A(B& B) : b(B){}
B b;
};
int main()
{
std::cout << std::is_trivially_constructible<B, B&>::value << '\n'; // Should print 1
std::cout << std::is_trivially_constructible<A, B&>::value << '\n'; // Should print 0
getchar();
return 0;
}
После прочтения и перечитывая то, что стандарт должен сказать об этом несколько раз (и удаление мой первый ответ дважды), я считаю, я наконец, нашел причину этой путаницы. См. Мой ответ. – Agentlien
После комментария @SebastianRedl я обновил свой ответ ** снова ** (вздох) .. – Agentlien