【问题标题】:Does `const &&` bind to all prvalues (and xvalues)?`const &&` 是否绑定到所有prvalues(和xvalues)?
【发布时间】:2014-07-24 20:12:30
【问题描述】:

C++标准定义了以下函数被删除;

template <class T>
void ref(const T&&) = delete;

template <class T>
void cref(const T&&) = delete;

这是为了通过禁止函数绑定到临时值(右值)来帮助确保函数不会被滥用。

  • const &amp;&amp; 是否绑定到所有右值,特别是纯右值?
  • const &amp;&amp; 是否会绑定到所有“移动对象”(xvalues;基本上是从std::move 或类似返回的东西)?

我可以推断它应该,但我没有任何“证据”。

  • 或者相反,是否存在右值(prvalue 或 xvalue)不会绑定到const &amp;&amp; 的情况?
    • 如果是,那又如何?

注意:来自 cmets 的一些澄清,这个问题严重影响了经典的右值,即纯右值值类别。

【问题讨论】:

  • “移动类型”是什么意思?
  • @JosephMansfield,从std::move 或类似返回的东西
  • 请注意:一般情况下,const T &amp;&amp; 无法在您的右值类型为 volatile T 时工作。但是这里推导出T,所以如果需要T可以推导出为volatile-qualified类型。
  • @user2485710: “你不会错理解 std::move 的作用”当然,只要有人告诉你 std::move 实际上不会移动任何东西。
  • 请注意std::move 总是返回一个右值 except 当参数是函数类型时——在这种情况下它返回一个左值,因为没有函数的右值类型。但是,“函数的右值引用”仍然会绑定到函数类型的左值。

标签: c++ c++11 language-lawyer rvalue-reference rvalue


【解决方案1】:

T const&amp;&amp; 可以绑定到Tconst T 类型的右值。

从 8.5.3 [dcl.init.ref] 第 5 段:

5 - 对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化,如下所示:[...]
— 否则,[...] 引用应为右值引用。 [...]
— 如果初始化表达式
— 是一个 xvalue、类纯右值、数组纯右值或函数左值,“cv1 T1”与“cv2 T2”引用兼容 [...] 然后引用绑定到初始化表达式的值 [...]

如果初始化表达式是非类类型的纯右值,则为引用绑定创建一个临时副本(同上)。

参考兼容性在 8.5.3p4 中定义;它需要相同或基类关系和相同或更大的 cv 限定。

因此,要将右值绑定到 T const&amp;&amp;,其 cv-qualification 必须不大于 const

【讨论】:

  • 但是正如 hvd 在问题 cmets 中指出的那样,因为推导了 T,所以该函数仍然可以采用 volatile-qualified 参数。 volatile 只是成为推导的T 的一部分。
【解决方案2】:

我想在这里添加一些经验证据来支持答案。

template <class T>
void ref(T&) {}

template <class T>
void ref(volatile T&) {}

template <class T>
void ref(volatile const T&) {}

template <class T>
void ref(const T&) {}

template <class T>
void ref(const T&&) = delete;

// xvalues
int&& ax();
const int&& bx();
volatile int&& cx();
volatile const int&& dx();

// prvalues
int ap();
const int bp();
volatile int cp();
volatile const int dp();

void test()
{
    ref(ax());
    ref(bx());
    ref(cx());
    ref(dx());

    ref(ap());
    ref(bp());
    ref(cp());
    ref(dp());
}

在这种情况下,所有对 ref 的调用都无法编译,包括带有 cv 限定变体的 xvalue 和 prvalue; msvc、gcc and clang 都因相应的“尝试引用已删除的函数”错误而导致编译失败。

【讨论】:

  • prvalues 在重载决议中被视为与 xvalues 相同
猜你喜欢
  • 2017-07-15
  • 2018-01-01
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 2017-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多