在上一个问题之后,我一直在研究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()&amp;
get()const&amp;
get()&amp;&amp;
get()const&amp;&amp;
这用clang和gcc 4.9.1编译并运行(尽管不是4.9.0)。直播sample here。
在一般代码中(样本用于查看代码如何编译和运行)。
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 &&
的“规范”签名会是什么样的?答案 0 :(得分:11)
关于const&&
的用处......(一般而言)
const&&
限定符对成员方法的有用性至多是最小的。不能以与&&
方法允许修改对象相同的方式修改对象;毕竟它是const
(如上所述,mutable
确实改变了这一点)。因此,我们无法消除它的内心,因为临时任务正在到期,就像我们在类似于正常move
的情况下那样。
在许多方面,const&&
的有用性可以在类型const T&&
的对象开始时的有用性的上下文中得到最好的评估。 const T&&
函数参数有用吗?正如另一个答案(对于这个问题)here所指出的,它们在声明删除的功能方面非常有用,例如在这种情况下
template <class T> void ref (const T&&) = delete;
明确禁止将prvalue和xvalue值类别类型的对象与函数一起使用,const T&&
执行bind to all prvalue and xvalue objects。
const&&
方法限定符的用处是什么?
值得注意的是,在提案C++ library extensions中,optional
,§5.3包含重载,例如
constexpr T value() const &&;
,其资格为const&&
,并被指定执行与&&
替代相同的操作。
我能推断出这个案子的原因;这是为了完整性和正确性。如果在右值上调用value()
方法,则它执行与const
无关的相同操作。 const
将需要由正在移动的包含对象或使用它的客户端代码处理。如果存在包含对象的某个mutable
状态,则可以合法地更改该状态。
这可能还有一些优点;没有特别的顺序...
= delete
以禁止该方法在prvalues和xvalues上使用。&&
方法相同的操作。这里的建议是标准库(及其扩展)的排序。
const&&
合格方法的“规范”签名会是什么样的?
由于该方法将执行与&&
方法相同的操作,因此我建议签名与&&
签名匹配。
答案 1 :(得分:9)
我们可以在文章What are const rvalue references good for?中找到对此问题的类似探索,并且突出显示的一个用途就是标准库中的这个示例:
template <class T> void ref (const T&&) = delete;
template <class T> void cref (const T&&) = delete;
完全禁用ref
和cref
rvalues。我们可以在draft C++11 standard部分20.8
功能对象段 2 中找到这些声明。
Scott Meyers在Universal References in C++11中暗示了这种用法:
即使简单添加const限定符也足以禁用 将“&amp;&amp;”解释为普遍参考:
答案 2 :(得分:3)
假设我们有一个mutable
状态的类型。然后const&&
将允许我们改变该状态,并指出这种突变是安全的。
struct bar;
struct foo {
mutable std::vector<char> state;
operator bar() const&;
operator bar() const&&;
};
const
不是绝对的。
除了可变状态之外,为了提取状态,在const
方法中抛弃const&&
是不安全的,因为从实际的const
对象中以这种方式提取状态是不确定的行为。
答案 3 :(得分:2)
我看到了对方法进行ref-qualifying的两个主要用途。一个就像你在get() &&
方法中展示的那样,你用它来选择一个可能更有效的实现,只有当你知道不再使用该对象时才能使用它。但另一个是安全提示,以防止在临时对象上调用某些方法。
在这种情况下,您可以使用get() const && = delete
之类的符号,但实际上我会保存这种方法来修改方法,尤其是那些可能代价高昂的方法。在不检索某些东西的情况下变异然后丢弃一个对象没有多大意义,如果执行变异是昂贵的话,那就更加有意义了。此构造为编译器提供了标记和阻止此类使用的方法。