ref-qualifier 'const &&' 有什么用?

What is use of the ref-qualifier `const &&`?

提问人:Niall 提问时间:7/18/2014 最后编辑:Niall 更新时间:6/19/2016 访问量:11656

问:

在上一个问题之后,我一直在挖掘 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() & get() const &

get() &
get() const &&

这使用 clang 和 gcc 4.9.1(虽然不是 4.9.0)编译和运行。现场样本在这里

在常规代码中(示例用于查看代码的编译和运行方式)。

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

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

  • 如果有的话,限定为的方法和限定为的方法之间隐含的语义差异是什么?即实现会有什么变化,或者你为什么想要两者?const &const &&
  • 真的能够被“移”出临时对象吗?std::string
  • 在这种情况下,“规范”签名会是什么样子?std::string get() const &&
C++ C++11 语言律师 move-semantics rvalue-reference

评论


答:

2赞 Michael Urman 7/18/2014 #1

我看到了引用限定方法的两个主要用途。一种是您在方法中显示的那样,您可以使用它来选择可能更有效的实现,该实现仅在您知道该对象将不再使用时才可用。但另一个是安全提示,以防止在临时对象上调用某些方法。get() &&

您可以像在这种情况下一样使用符号,尽管实际上我会保留这种方法来修改方法,尤其是那些可能成本高昂的方法。在不检索某些东西的情况下进行突变然后丢弃对象没有多大意义,如果执行突变的成本很高,则加倍意义。此构造为编译器提供了一种标记和防止此类使用的方法。get() const && = delete

评论

0赞 Niall 7/18/2014
这给了你很多关于如何使用对象的控制权,我认为这将是一般用途(如果有的话)。=deleteconst&&
12赞 Shafik Yaghmour 7/18/2014 #2

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

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

这将完全禁用 和 for 右值。我们可以在 C++11 标准草案函数对象2 段中找到这些声明。refcref20.8

Scott Meyers在C++11的通用引用中提到了这种用法:

即使简单地添加一个 const 限定符也足以禁用 将“&&”解释为通用引用:

评论

0赞 Niall 7/18/2014
我想我同意这篇文章,总的来说,尤其是对于 ref-qualified 方法,除了禁止使用它之外几乎没有用处。
0赞 Ben Voigt 7/19/2014
请注意,在该文章之前,有多个关于 SO 的相关问题。例如,stackoverflow.com/q/4938875/103167
0赞 Shafik Yaghmour 7/19/2014
@BenVoigt有一些,但我并没有超出我的第一个搜索命中,因为它很好地回答了这个问题,而且它实际上以非常相似的方式巧妙地探讨了这个问题。不过,这个问题是迄今为止最好的质量。
0赞 Potatoswatter 8/8/2014
无论如何,ref 限定符从不指示通用引用。我不明白这个答案与这个问题有什么关系。
0赞 BЈовић 10/1/2014
你的答案不是很清楚。真的只取 r 值吗?为什么不只实施?在这种情况下,尝试传递 r 值将失败。如果你写的是真的,那么它是愚蠢的使用const T&&template <class T> void ref (const T&)const T&&
24赞 Niall 8/6/2014 #3

关于 const&&&...(一般情况)

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

在许多方面,最好在类型对象的有用性开始的上下文中评估 的有用性。const T&& 函数参数有多大用处?正如此处(针对此问题)的另一个答案所指出的,它们在声明已删除的函数时非常有用,例如在本例中const&&const T&&

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

显式禁止 PRVeValue 和 Xvalue 值类别类型的对象与函数一起使用,并绑定到所有 PRVeValue 和 Xvalue 对象const T&&

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

有趣的是,在提案中,C++ 库扩展 § 5.3 包括重载,例如optional

constexpr T value() const &&;

被限定为并指定执行与替代项相同的操作。const&&&&

对于这种情况,我可以推断出的原因;这是为了完整性和正确性。如果在右值上调用该方法,则无论它是否存在,它都会执行相同的操作。遗嘱需要由被移动的包含对象或使用它的客户端代码来处理。如果包含对象的某个状态,则可以合法地更改该状态。value()constconstmutable

这很可能还是有一些优点的;排名不分先后...

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

对于合格方法,“规范”签名会是什么样子?const&&

由于该方法将执行与该方法相同的操作,因此我主张签名与签名匹配。&&&&

评论

1赞 Potatoswatter 8/8/2014
“如果你正在实现一个通用的容器类型,那么为了完整性和正确性,请考虑添加它并执行与&&方法相同的操作。将改为调用限定的方法进行右值对象访问。constconst &const
0赞 Niall 8/8/2014
@Potatoswatter。它是如何在 et 的 C++ 库扩展中指定的。铝。和 方法的作用相同(n4082,第 5.3.5 节第 11、20 段等)。值得注意的是,GCC 在给定常量右值的情况下选择正确的方法时存在问题,但 clang 没有。我认为这里的重点是,一般来说,没有用,但有一些极端情况可能只是需要它(然后仔细考虑为什么需要它)。optional&&const&&
5赞 Yakk - Adam Nevraumont 8/7/2014 #4

假设我们有一个带有状态的类型。然后既允许我们突变该状态,又表明这种突变是安全的。mutableconst&&

struct bar;

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

const不是绝对的。

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

评论

0赞 Niall 8/7/2014
mutable带来了一些非常有趣的东西,因为它在 C++11 中也说明了线程安全。
0赞 Yakk - Adam Nevraumont 8/7/2014
@niall仅在容器中。或由 提供的类型。stdstd
0赞 Niall 8/7/2014
这是一个很好的观点。我同意,从技术上讲是的。不过,从个人角度来看,我通常希望类型可以与标准库一起使用。鉴于目前在一般实现中发现的一致性水平,我认为我们都可以或应该 - 如果不是这样,那将是违反直觉的。我认为标准库为我们提供了一个相当好的模型。我也理解这并不总是适用的想法 - 但我认为这些情况是或应该受到限制的(我知道一些)。