C++ 什么';在引用限定符上重载成员函数的用例是什么?
C++11允许基于引用限定符重载成员函数:C++ 什么';在引用限定符上重载成员函数的用例是什么?,c++,c++11,overloading,rvalue-reference,qualifiers,C++,C++11,Overloading,Rvalue Reference,Qualifiers,C++11允许基于引用限定符重载成员函数: class Foo { public: void f() &; // for when *this is an lvalue void f() &&; // for when *this is an rvalue }; Foo obj; obj.f(); // calls lvalue overload std::move(obj).f(); // calls rvalue ov
class Foo {
public:
void f() &; // for when *this is an lvalue
void f() &&; // for when *this is an rvalue
};
Foo obj;
obj.f(); // calls lvalue overload
std::move(obj).f(); // calls rvalue overload
我理解这是如何工作的,但它的用例是什么
我看到有人提议将标准库中的大多数赋值运算符限制为左值目标(即,向赋值运算符添加“&
”引用限定符),但是。所以这是一个潜在的用例,委员会决定不使用它。那么,什么是合理的用例呢?一个用例是
然而,不使用引用限定符会让您在两个坏选项之间进行选择
T operator*(T const& lhs, T const& rhs); // can be used on rvalues
const T operator*(T const& lhs, T const& rhs); // inhibits move semantics
第一个选项允许移动语义,但在用户定义类型上的行为与在内置类型上的行为不同(与ints不同)。第二种选择将停止分配,但消除移动语义(例如矩阵乘法可能会影响性能)
注释中@dyp的链接还提供了关于使用其他(
&&&
)重载的扩展讨论,如果您想分配给(左值或右值)引用,这可能很有用。如果f()需要一个作为其副本并经过修改的Foo-temp,在提供引用getter的类中,可以修改tempthis
,而在提供引用getter的类中,ref限定符重载可以在从右值提取时激活移动语义。例如:
class some_class {
huge_heavy_class hhc;
public:
huge_heavy_class& get() & {
return hhc;
}
huge_heavy_class const& get() const& {
return hhc;
}
huge_heavy_class&& get() && {
return std::move(hhc);
}
};
some_class factory();
auto hhc = factory().get();
这看起来确实需要花费大量的精力,只为了拥有更短的语法
auto hhc = factory().get();
与
auto hhc = std::move(factory().get());
编辑:我找到了,它提供了三个激励示例:
运算符=
约束为左值(TemplateRex的答案)运算符&
约束为左值。我认为,当“指针”最终被解除引用时,确保“指针对象”更有可能处于活动状态是明智的:不能说我个人曾经使用过
操作符&
重载。一方面,你可以使用它们来防止调用临时变量时语义上无意义的函数被调用,例如操作符=
或改变内部状态并返回void
的函数,通过添加和作为参考限定符
另一方面,您可以使用它进行优化,例如当您有一个右值引用时,将一个成员作为返回值移出对象,例如,函数getName
可以根据引用限定符返回std::string const&
或std::string&
另一个用例可能是返回对原始对象的引用的操作符和函数,例如Foo&operator+=(Foo&)
,可以专门化为返回右值引用,从而使结果可移动,这同样是一种优化
TL;DR:用它来防止函数的不正确使用或优化。更一般地说:防止公开指向临时文件内部数据的引用或指针。你什么时候希望它们是可分配的?@Mehrdad我不知道,但是如果你不指定&
,它们会很有趣。@TemplateRex:interest。我觉得这可以通过完全禁止通过=rhs
分配右值来解决,而不是引入这个更一般的构造。如果人们真的想给右值赋值,他们可以只做。operator=(rhs)
。@Mehrdad这可能不会让编译器编写者的生活变得复杂,这并不令人惊讶:-)巨重类&&get()&
是错误的(导致一个悬空引用,应该是巨重类get()&
),和auto hhc=std::move(factory().get())
将是多余的。@ildjarn为什么您关心的是返回右值引用,而不是返回左值引用?一个不比另一个更容易摇摆。是的,这篇文章的重点是要编写大量代码,以避免需要编写std::move(factory().get())
-我想我需要更清楚地说明这一点。因为左值引用只针对左值返回,因此不成问题……我将此标记为答案,因为它很好地总结了情况,它还链接到原始提案。
auto hhc = std::move(factory().get());
struct S {
T operator &() &;
};
int main() {
S foo;
auto p1 = &foo; // Ok
auto p2 = &S(); // Error
}