2013-04-26 1 views
3

Это небольшая проблема, с которой я запутался, я не знаю, как ее описать, поэтому просто см. Коды ниже:неверный результат для std :: is_trivially_constructible <T, T&> :: значение, когда T объявлено T :: T (T &)

struct B { 
    B() {} 
    B(B&) { 
    std::cout << "not trivial\n"; 
    } 
}; 

int main() { 
    B b1; 
    B b2(b1); 
    std::cout << std::is_trivially_constructible<B, B&>::value << '\n'; 
    return 0; 
} 

выход:

not trivial 
1 

Я использую VS11.

EDIT:

Я просто проверил пример http://en.cppreference.com/w/cpp/types/is_constructible часть продукции неверен.

#include <iostream> 
#include <type_traits> 

class Foo { 
    int v1; 
    double v2; 
public: 
    Foo(int n) : v1(n), v2() {} 
    Foo(int n, double f) : v1(n), v2(f) {} 
}; 
int main() { 
    std::cout << "Foo is ...\n" << std::boolalpha 
       << "\tTrivially-constructible from const Foo&? " 
       << std::is_trivially_constructible<Foo, const Foo&>::value << '\n' 
       << "\tTrivially-constructible from int? " 
       << std::is_trivially_constructible<Foo, int>::value << '\n' 
       << "\tConstructible from int? " 
       << std::is_constructible<Foo, int>::value << '\n' 
} 

выход:

Foo is ... 
     Trivially-constructible from const Foo&? true 
     Trivially-constructible from int? true//Trivially-constructible from int? false 
     Constructible from int? true 
Press any key to continue . . . 
+0

После прочтения и перечитывая то, что стандарт должен сказать об этом несколько раз (и удаление мой первый ответ дважды), я считаю, я наконец, нашел причину этой путаницы. См. Мой ответ. – Agentlien

+0

После комментария @SebastianRedl я обновил свой ответ ** снова ** (вздох) .. – Agentlien

ответ

4

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; 

}

+0

Мне нравится объяснение. – arne

+0

@arne спасибо. Я вложил в это много усилий. – Agentlien

+0

Я не знаю, что вы подразумеваете под «нетривиальной операцией» (по сути, нетривиальный оператор или конструктор) », но даже если я вызову виртуальную функцию внутри этой копии ctor, результат будет равен 1 и увидит мой EDIT , выход отличается от результата, заданного http://en.cppreference.com/w/cpp/types/is_constructible – Frahm

1

От http://en.cppreference.com/w/cpp/types/is_constructible:

"выражение конструктор не вызывает какой-либо операции, которая не является тривиальным". и это тот случай, когда вы пишете

B(B&); 

Ничего особенного в этом нет, вы просто передаете ссылку.

+0

тривиальные средства не объявляются, поэтому я думаю, что вывод неверен. – Frahm

+0

Как я понимаю, это означает, что оператор с выражением конструктора, то есть оператор, вызывающий конструктор, не требует вызова каких-либо других нетривиальных операций, таких как вычисления, которые не могут быть выполнены во время компиляции или вызовы функций. – arne

+1

Я думаю, что операция «std :: cout <<» не тривиальная \ n ";" не может быть выполнена во время компиляции. – Frahm

 Смежные вопросы

  • Нет связанных вопросов^_^