2016-02-20 2 views
4

Не лучше использовать std::declval объявленные в форме:Т declval() вместо T && declval() для common_type

template< class T > T declval(); // (1) 

тогда текущий:

template< class T > T && declval(); // (2) 

для std::common_type (возможно, с другим именем только для этой текущей цели)?

Поведения common_type использования (1) ближе к поведению тройного оператора (но не с помощьюstd::decay_t), чем поведение при использовании (2):

Live example.

Каковы недостатки этого подхода? Верно ли, что для (1) в decltype() тип контекста T должен быть конструктивным (вообще-то должен иметь хотя бы один конструктор) и/или разрушаемым?

Reference article сказал:

Для неспециализированной станд :: common_type, правила для определения общего типа между каждой парой Т1, Т2 точно правила для определения типа возвращаемого тройного условного оператора в unevaluated context, с произвольным первым аргументом типа bool и с xvalues of type T1 and T2 (since C++17)std::declval<T1>() and std::declval<T2>() (until C++17) в качестве второго и третьего операндов. The common type is the result of std::decay applied to the type of the ternary conditional (since C++14).

Я думаю, что это весьма вероятно, последнее предложение (emphasized) должен быть не только since C++14, но и until C++17 быть справедливым. В противном случае 1-е предложение цитирования не будет выполнено даже после C++ 17 и будет обнаружен некоторый дефект.

В should-stdcommon-type-use-stddecay есть некоторые пояснения относительно проблем std::common_type, но это только справочная информация по текущему вопросу.

+0

Для начала это прерывается, если тип имеет удаленный деструктор или не может быть возвращен из функции (например, абстрактные типы, типы массивов, типы функций). –

+0

@ T.C. Я думаю, что для этих типов * тернарный оператор * из текущей реализации по умолчанию 'std :: common_type' также не имеет смысла, но специализации. – Orient

+1

@ T.C. На самом деле нам просто нужна функция языка, которая «дает мне выражение типа' T' » – Barry

ответ

2

Преимущество:

template <class T> T&& declval(); 

является то, что он работает для любого типа T, а просто возвращение T не будет работать для типов, которые не являются не возвратная (например, функции, массивы) и типы, которые не являются (например, частный/защищенный/удаленный деструктор, абстрактные базовые классы).

Конечно, distandvantage что common_type<int, int> заканчивается время int&&, а затем вам нужно добавить decay что делает common_type<int&, int&> быть int - который не имеет смысла либо. Здесь просто нет победы.


В конце концов, я думаю, что нам просто нужно немного особенность языка, что, в невычисленного контексте является «дать мне что-то типа T», который работает для любого T, что действительно дает вам T (а не a T&&).

+1

«Дайте мне что-то типа Т». Именно это делает 'declval'. Он дает вам lvalue типа 'T', если вы даете ему' T & 'и xvalue (modulo 'void' (prvalue) и типы функций (lvalue)) типа' T', если вы дадите ему 'T' или' Т && '. Если вы хотите использовать prvalues, который поставляется с собственными ловушками - в дополнение к примерам, которые я дал ранее, он отбрасывает cv-квалификаторы для типов неклассов. –