提问者:小点点

ref限定符`const&&'有什么用?


在前面的一个问题之后,我对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();
}

输出与您预期的一样:

get()(&S;
get()常量(&P;
获取()&&
get()常量(&&)

这将编译并使用clang和GCC4.9.1(但不是4.9.0)运行。 活体样本在这里。

在一般代码中(示例是为了查看代码是如何编译和运行的)。

  • 方法上的常量&引用限定符的用途是什么?

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

  • 限定为const&的方法和限定为const&的方法之间隐含的语义差异是什么(如果有的话)? 即。 实现会有什么变化,或者为什么同时需要?
  • std::string真的能够从临时对象中“移”出来吗?
  • 在这种情况下,std::string get()const&的“规范”签名是什么样子的?

共3个答案

匿名用户

关于const&&.。。 (一般)

成员方法上的const&&限定符的用处最小。 修改对象的方式不能与&&方法允许修改对象的方式相同; 毕竟,它是const(如前所述,mutable确实改变了这一点)。 因此,我们将无法撕开它的内脏,因为临时文件无论如何都将到期,就像我们在类似于正常的移动的情况下一样。

在许多方面,const&的有用性可以在const&类型的对象的有用性的上下文中进行最佳评估。 常量&&函数参数有多有用? 正如在这里(对这个问题)的另一个回答中指出的,它们在声明删除的函数时非常有用,例如在这种情况下

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

要显式禁止prvalue和xvalue值类别类型的对象与函数一起使用,常量T&&确实绑定到所有prvalue和xvalue对象。

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

有趣的是,在C++库扩展的建议中,可选,§5.3,包含了重载,例如。

constexpr T value() const &&;

它们被限定为const&&,并被指定为执行与&&备选项相同的操作。

我能推断出这个案子的原因; 这是为了完整和正确。 如果对rvalue调用value()方法,则它执行相同的操作,而不依赖于它是否为const常量将需要被移动的包含对象或使用它的客户端代码来处理。 如果包含对象时存在某种mutable状态,则可以合法地更改该状态。

这样做很可能还是有一些好处的; 不分先后。。。

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

const&&限定方法的“规范”签名是什么样子的?

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

匿名用户

我们可以在文章What are constrvalue references good for? 其中一个突出的用法是标准库中的这个例子:

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

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

ScottMeyers在C++11的通用引用中提到了这个用法:

即使简单地添加一个常量限定符,也足以禁止将“&&"解释为一个通用引用:

匿名用户

假设我们有一个具有mutable状态的类型。 则const&&将允许我们改变该状态,并指示这种改变是安全的。

struct bar;

struct foo {
  mutable std::vector<char> state;
  operator bar() const&;
  operator bar() const&&;
};

常量不是绝对的。

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