1.問題
右辺値と左辺値の参照メンバー関数に関して、メンバー関数は通常、オブジェクトが左辺値であるか右辺値であるかに関係なく、オブジェクトで呼び出されます。
string s1 = "a value",s2 = "another";
auto n = (s1 + s2).find('a');
s1 + s2 = "wow";
2.定義
上記の式は右辺値を割り当てます。この式を防ぐために、新しい標準では、パラメータリスト修飾子の後に参照を配置することにより、左のオペランド(this)が指すオペランドを強制的に左辺値にすることができます。
class Foo {
public:
Foo& operator=(const Foo&)& {
return *this;
}
Foo& retFoo() {
; //返回一个引用,retFoo调用是一个左值
return *this;
}
Foo retVal() {
; //返回一个值,retVal调用是一个右值
return Foo();
}
};
その後、
Foo i, j; //i,j是左值
i = j;
retFoo() = j; //正确,retFoo()返回一个左值
retVal() = j; //错误,retVal()返回一个右值
i = retVal(); //正确
j= retFoo(); //正确
2.1 &&を使用して、「左側のオペランドは右辺値です」を強制的に指定できます。
inline void StrVec::push_back(std::string &&s)
{
chk_n_alloc(); // reallocates the StrVec if necessary
alloc.construct(first_free++, std::move(s));
}
2.2 const修飾子と同様に、参照修飾子は非静的メンバー関数にのみ使用できます
2.3関数の宣言と定義に同時に現れる必要があります。
3.constおよび参照修飾子
関数はconst修飾子と参照修飾子の両方を使用できます。この場合、参照修飾子はconst修飾子の後に続く必要があります。
class Foo{
public:
Foo someMes() & const; //错误,const限定符必须在前
Foo someMes() const &; //正确,const限定符必须在前
};
データメンバーを変更しない関数は、const型として宣言する必要があります。
4.過負荷
4.1定義
参照修飾子は、オーバーロードされたバージョンを区別するために使用できます。「&&は、戻り値が右辺値であることを示します」。また、参照修飾子とconstを組み合わせて、メンバー関数のオーバーロードされたバージョンを区別できます。
class Foo{
public:
Foo sorted() &&; //可用于改变的右值
Foo sorted() const &; //可用于任何类型的Foo
private:
vector<int> data;
};
//本对象是右值,因此可以原址排序
Foo Foo::sorted() &&
{
sort(data.begin(),data.end());
return *this;
}
//本对象是const或是一个左值,哪种情况我们都不能对其进行原址排序
Foo Foo::sorted() const &
{
Foo ret*(*this); //拷贝一个副本
sort(ret.begin(),ret.end()); //排序副本
return ret; //返回副本
}
retVal.sorted(); //retVal()是一个右值,调用Foo::sorted() &&
retFoo.sorted(); //retFoo()是一个左值,调用Foo::sorted() const &
4.2使用制限
- constメンバー関数を定義する場合、2つのバージョンを定義できます。唯一の違いは、一方のバージョンはconst修飾されており、もう一方はそうではないことです。
- 参照修飾関数は同じではありません。同じ名前と同じパラメーターリストを持つ2つ以上のメンバー関数を定義する場合は、すべての関数に参照修飾子を追加する必要があります。追加しない場合は、次のようにします。
class Foo
{
Foo sorted() &&;
Foo sorted() const; //错误,必须加上引用限定符
using Comp = bool (const int&,const int&);
Foo sorted(Comp*); //正确,不同的参数列表
Foo sorted(Comp*); //正确,两个版本都没有使用引用限定符
};