我试图弄清楚在is_assignable的实现中如何解释declval ()= declval ()。

declval将类型转换为引用。鉴于此,我将表达式转换为以下四种可能性之一:

  • _Dest && = _Src &&
  • _Dest && = _Src&
  • _Dest&= _Src &&
  • _Dest&= _Src&

  • 然后,我创建了两个辅助函数。
    template <typename T> T rvalue();
    template <typename T> T& lvalue();
    

    我的理解是可以使用模板函数来实现这四个表达式。
  • _Dest && = _Src && -----> rvalue ()= rvalue ()

  • 其他三个也一样。

    然后,我通过编译三对具体类型的每种可能性的模板化函数版本,来模拟decltype(declval ()= declval (),..)。
  • _Dest = int,_Src = int。编译器接受#3和#4。 is_assignable对于#3和#4返回true。他们同意了。
  • _Dest = int,_Src = double。与
  • 相同的结果
  • _Dest = double,_Src = int。对于这一点,编译器和is_assignable不同意。编译器再次不喜欢分配给右值。但是,is_assignable对于所有四种可能性都返回true。

  • 我的问题是
  • 我是否正确解释了declval ()= declval ()?换句话说,这是否真的转化为四种可能性。如果是,可以将每个映射到一个模板化函数表达式吗?
  • 为什么在_Dest = double,_Src = int情况下,编译器和is_assignable意见不同?

  • 谢谢。

    最佳答案

    std::declval实际上被指定为(C++ 11§20.2.4[declval] p1):

    template <class T>
    typename add_rvalue_reference<T>::type declval() noexcept;
    

    引用折叠规则(第8.3.2节[dcl.ref] p6)的结果是,当declval是左值引用类型时,T返回左值引用,否则返回右值引用。是的,您的解释是正确的。

    如果您的编译器认为double&&可从任何类型分配,则它有一个bug。 §5.17[expr.ass] p1指出:



    [强调我的]。

    许多程序员选择使用左值引用限定符声明赋值运算符,以使用自己的类型来模拟这种行为-仅对左值进行赋值:
    class foo {
      foo& operator = (const foo&) & = default;
      foo& operator = (foo&&) & = default;
    };
    

    09-06 16:27