什么是ref-qualifier`const &&`的用法?

Nia*_*all 22 c++ rvalue-reference language-lawyer move-semantics c++11

在上一个问题之后,我一直在研究ref-qualifiers.

给出下面的代码示例;

#include <iostream>
#include <string>
#include <utility>

struct A {
  std::string abc = "abc";
  std::string& get() & {
    std::cout << "get() &" << std::endl;
    return abc;
  }
  std::string get() && {
    std::cout << "get() &&" << std::endl;
    return std::move(abc);
  }
  std::string const& get() const & {
    std::cout << "get() const &" << std::endl;
    return abc;
  }
  std::string get() const && {
    std::cout << "get() const &&" << std::endl;
    return abc;
  }
};

int main()
{
  A a1;
  a1.get();
  const A a2{};
  a2.get();
  A().get();
  const A a3{};
  std::move(a3).get();
}
Run Code Online (Sandbox Code Playgroud)

输出正如您所期望的那样:

get()&
get()const&
get()&&
get()const &&

这用clang和gcc 4.9.1编译并运行(尽管不是4.9.0).现场样品.

在一般代码中(样本可以看到代码如何编译和运行).

  • const &&ref-qualifier对方法的目的是什么?

该方法无法修改对象上的内容(它是const),尝试return std::move(abc);从该const &&方法实际上根本不移动std::string.据推测,您可能希望能够修改对象,因为它是一个r值并且不会长时间存在.如果const &&要删除限定方法,代码std::move(a3).method()将绑定到const &限定方法,这是有意义的.

  • 如果有的话,隐含的语义差异在一个合格的方法const &和一个合格的方法之间是const &&什么?即如何实施变化或为什么你想要两者?
  • 请问std::string忠实地能够被"搬"出来的临时对象的?
  • std::string get() const &&在这种情况下,"规范"签名会是什么样的?

Nia*_*all 12

关于...的用处const&&(一般情况下)

const&&限定符对成员方法的有用性充其量是最小的.不能以与&&允许修改方法相同的方式修改对象; const毕竟它(如上所述,mutable确实改变了这一点).因此,我们无法撕掉它的胆量,因为临时任期正在到期,就像我们想要的类似于正常情况一样move.

在许多方面,const&&可以在类型对象const T&&开始有用的背景下最好地评估其有用性.函数参数有用const T&&吗?正如这里的另一个答案(对于这个问题)所指出的,它们在声明删除的函数时非常有用,例如在这种情况下

template <class T> void ref (const T&&) = delete;
Run Code Online (Sandbox Code Playgroud)

到明确禁止prvalue和x值值类别类型的对象从与所述功能被使用,并且const T&&结合到所有prvalue和x值的对象.

const&&方法限定符的用处是什么?

值得注意的是,在提案C++库扩展optional,第5.3节包含了重载,例如

constexpr T value() const &&;
Run Code Online (Sandbox Code Playgroud)

被限定为const&&和被指定执行与&&替代相同的操作.

我能推断出这个案子的原因; 这是为了完整性和正确性.如果在value()rvalue上调用该方法,则它执行与之相关的相同操作const.在const将需要通过移动所包含的对象或使用它的客户端代码来处理.如果存在某个mutable包含对象的状态,则可以合法地更改该状态.

这可能还有一些优点; 没有特别的顺序......

  • 声明它= delete禁止方法在prvalues和xvalues上使用.
  • 如果类型具有可变状态且限定符在目标环境中有意义(可能除了其他限定符之外),请考虑它.
  • 如果要实现通用容器类型,那么为了完整性和正确性,请考虑添加它并执行与&&方法相同的操作.这里的建议是从标准库(及其扩展)中排序.

对于const&&合格的方法,"规范"签名会是什么样的?

由于该方法将执行与该&&方法相同的操作,我建议签名与签名匹配&&.


Sha*_*our 9

我们可以在文章中找到类似的探索这个问题什么是const rvalue引用有用?并且突出的一个用途是这个例子形成标准库:

template <class T> void ref (const T&&) = delete;
template <class T> void cref (const T&&) = delete;
Run Code Online (Sandbox Code Playgroud)

它完全禁用refcrefrvalues.我们可以在草案C++ 11标准部分20.8 函数对象2段中找到这些声明.

Scott Meyers 在C++ 11的Universal References中暗示了这种用法:

即使简单地添加const限定符也足以禁用"&&"作为通用引用的解释:


Yak*_*ont 5

假设我们有一个带有状态的类型mutable。然后const&&将允许我们改变该状态,并表明这种改变是安全的。

struct bar;

struct foo {
  mutable std::vector<char> state;
  operator bar() const&;
  operator bar() const&&;
};
Run Code Online (Sandbox Code Playgroud)

const不是绝对的。

const除非可变状态,否则为了提取状态而在方法中放弃是不安全的const&&,因为以这种方式从实际const对象中提取状态是未定义的行为。