LibС++ vs libstdС++ std:: is_move_assignable: что является наиболее правильным?
Я пытаюсь получить более глубокое понимание С++, прочитав стандарт С++ 14 вместе с источником libС++ и libstdС++. Реализация различных элементов type_traits
варьируется между двумя, особенно is_move_assignable
, и я пытаюсь выяснить, какая из них "более правильная".
LibС++:
template <class _Tp> struct is_move_assignable
: public is_assignable<typename add_lvalue_reference<_Tp>::type,
const typename add_rvalue_reference<_Tp>::type> {};
libstdС++:
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_move_assignable_impl;
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, false>
: public false_type { };
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, true>
: public is_assignable<_Tp&, _Tp&&>
{ };
template<typename _Tp>
struct is_move_assignable
: public __is_move_assignable_impl<_Tp>
{ };
Стандартные состояния:
Для ссылочного типа T
, тот же результат, что и is_assignable<T&, T&&>::value
, иначе false
.
Первое, что я заметил, это то, что libС++ применяет const
ко второму параметру шаблона, что не кажется правильным, поскольку оператор присваивания переходов принимает неконстантное значение r. libstdС++ также использует __is_referenceable
, который следует за формулировкой стандарта, но libС++ этого не делает. Это требование распространяется на использование libС++ add_lvalue_reference
и add_rvalue_reference
, которые обе обеспечивают __is_referenceable
самостоятельно?
Я был бы очень признателен за понимание того, почему каждый проект выбрал свои решения!
Ответы
Ответ 1
Для любой справки, две реализации выполняют одно и то же, поскольку посторонний const
в libС++ бессмыслен, но и безвреден.
(Судя по различию, это, безусловно, выглядит как временное безумие для меня:) Кажется, проблема C & P из (неправильной) реализации is_copy_assignable
.)
Для любых не ссылочных (т.е. cv void
или отвратимых типов функций) libstdС++ возвращает false_type
.
В libС++, add_{l,r}value_reference
возвращает его без изменений (это зависит от разрешения проблемы, которое отправляет С++ 14). Поверхность const
сверху ничего не делает для AFT и добавляет const
для типов void
y.
Затем переходим к is_assignable
, который SFINAE-проверяет корректность declval<T>() = declval<U>()
для T == U == some AFT
или T == some void type
и U = some const-qualified void type
. Во всех случаях выражение плохо сформировано (с помощью SFINAE-friendly), поэтому мы получаем false_type
назад.
Оба эквивалентны.
Ответ 2
Спасибо! Любая идея, почему авторы могли добавить const
, то?
Мое лучшее предположение - временное (надеюсь) безумие:
https://github.com/llvm-mirror/libcxx/commit/6063ec176d5056683d6ddd310c2e3a8f1c7e1b46#diff-48f5ee43879b5ad38888f0a6ead10113R1245
; -)
Я удалил const
и выполнил текущие модульные тесты, и ничего не получилось.
Ответ 3
__is_referenceable
- нестандартная внутренняя процедура libstdС++. (Это не значит, что это плохо, просто я бы не ожидал, что libС++ будет использовать его). Кроме того, концепция "ссылочная" появилась гораздо позже is_move_assignable
.
__is_referenceable
помогает при работе с "отвратительными функциями"; такие вещи, как int (*) (double) &&
.
Похоже, мне нужно написать больше тестов: -)