libc++ vs libstdc++ std::is_move_assignable:哪个最正确?

libc++ vs libstdc++ std::is_move_assignable: Which is the most correct?

我试图通过阅读 C++14 标准以及 libc++ 和 libstdc++ 的源代码来更深入地了解 C++。各种 type_traits 项目的实现在两者之间有所不同,特别是 is_move_assignable,我试图弄清楚它们中的哪一个是 "more correct."

libc++:

template <class _Tp> struct is_move_assignable
    : public is_assignable<typename add_lvalue_reference<_Tp>::type,
                           const typename add_rvalue_reference<_Tp>::type> {};

libstdc++:

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>
  { };

标准规定:

For a referenceable type T, the same result as is_assignable<T&, T&&>::value, otherwise false.

我注意到的第一件事是 libc++ 将 const 应用于第二个模板参数,这似乎不正确,因为移动赋值运算符采用非 const 右值。 libstdc++也使用__is_referenceable,遵循标准的写法,但libc++没有。 libc++ 对 add_lvalue_referenceadd_rvalue_reference 的使用是否涵盖了这一要求,它们都强制执行 __is_referenceable

如果能深入了解每个项目为何选择他们的解决方案,我将不胜感激!

Thanks! Any idea why the authors might have added const, then?

我最好的猜测是暂时的(希望)精神错乱:

https://github.com/llvm-mirror/libcxx/commit/6063ec176d5056683d6ddd310c2e3a8f1c7e1b46#diff-48f5ee43879b5ad38888f0a6ead10113R1245

;-)

我删除了 const 和 运行 当前的单元测试并且没有失败。

__is_referenceable 是一个非标准的内部 libstdc++ 例程。 (这并不意味着它不好,只是我不希望 libc++ 使用它)。此外,"is referenceable" 概念的出现比 is_move_assignable 晚得多。

__is_referenceable 有助于处理 "abominable functions"; int (*) (double) &&.

之类的东西

看来我需要编写更多测试:-)

对于任何可引用的内容,这两个实现做同样的事情,因为 libc++ 中无关的 const 没有意义但也无害。

(从差异来看,这对我来说肯定是暂时的精神错乱:)似乎是 is_copy_assignable 的(错误)实现的 C&P 问题。)

对于任何不可引用的东西(即 cv void 或可恶的函数类型),libstdc++ returns false_type.

在 libc++ 中,add_{l,r}value_reference returns 它没有变化(这取决于晚于 C++14 的问题解决方案)。在顶部洒一个 const 对 AFT 没有任何作用,并为 voidy 类型添加一个 const

然后我们转到 is_assignable,SFINAE 测试 declval<T>() = declval<U>() 的良构性,对于 T == U == some AFTT == some void typeU = some const-qualified void type。在所有情况下,表达式都是错误的(以 SFINAE 友好的方式),所以我们得到 false_type 返回。

两者是等价的