簡體   English   中英

成員函數簽名末尾的 &(與號)是什么意思?

[英]What does the & (ampersand) at the end of member function signature mean?

我不記得是哪個演講了,但最近我看了一些來自 CppCon 2017 的演講,有人提到作為某種旁注,重載operator=的唯一真正方法是以下方式:

class test {
public:
    test& operator=(const test&) &;
};

他明確強調了尾隨&但沒有說明它的作用。

那么它有什么作用呢?

引用限定符 - 在 C++11 中引入

Ref-qualifiers 不是 C++17 特性(查看問題的標簽),而是 C++11 中引入的特性。

struct Foo
{
  void bar() const &  { std::cout << "const lvalue Foo\n"; }
  void bar()       &  { std::cout << "lvalue Foo\n"; }
  void bar() const && { std::cout << "const rvalue Foo\n"; }
  void bar()       && { std::cout << "rvalue Foo\n"; }
};

const Foo&& getFoo() { return std::move(Foo()); }

int main()
{
  const Foo c_foo;
  Foo foo;

  c_foo.bar();            // const lvalue Foo
  foo.bar();              // lvalue Foo
  getFoo().bar();         // [prvalue] const rvalue Foo
  Foo().bar();            // [prvalue] rvalue Foo

  // xvalues bind to rvalue references, and overload resolution
  // favours selecting the rvalue ref-qualifier overloads.
  std::move(c_foo).bar(); // [xvalue] const rvalue Foo
  std::move(foo).bar();   // [xvalue] rvalue Foo
}

請注意,右值可用於初始化 const 左值引用(並因此擴展由右值標識的對象的生命周期),這意味着如果我們從上面的示例中刪除右值引用限定符重載,則右值值類別在示例中都將支持剩余的const &重載:

struct Foo
{
  void bar() const & { std::cout << "const lvalue Foo\n"; }
  void bar()       & { std::cout << "lvalue Foo\n"; }
};

const Foo&& getFoo() { return std::move(Foo()); }

int main()
{
  const Foo c_foo;
  Foo foo;

  // For all rvalue value categories overload resolution
  // now selects the 'const &' overload, as an rvalue may
  // be used to initialize a const lvalue reference.
  c_foo.bar();            // const lvalue Foo
  foo.bar();              // lvalue Foo
  getFoo().bar();         // const lvalue Foo
  Foo().bar();            // const lvalue Foo
  std::move(c_foo).bar(); // const lvalue Foo
  std::move(foo).bar();   // const lvalue Foo
}

有關簡要介紹,請參見例如以下博客文章:


右值不能調用非const &重載

為了可能解釋你從 CppCon 談話中回憶的引述的意圖,

“……這是重載operator=的唯一真正方法……”

我們訪問[over.match.funcs]/1, /4 & /5 [強調我的]:

/1 [over.match.funcs] 的子條款描述了在使用重載決議的每個上下文中提交給重載決議的候選函數集和參數列表。 ...

/4對於非靜態成員函數,隱式對象參數的類型為

  • (4.1) — “對 cv X左值引用”,用於未使用 ref 限定符或使用& ref 限定符聲明的函數

  • (4.2) — 使用&& ref 限定符聲明的函數的“對 cv X右值引用”

其中X是函數所屬的類,cv 是成員函數聲明中的 cv 限定。 ...

/5 ... 對於沒有引用限定符聲明的非靜態成員函數,附加規則適用

  • (5.1) — 即使隱式對象參數不是 const 限定的,只要參數在所有其他方面都可以轉換為隱式對象參數的類型,就可以將右值綁定到參數。 [ 注意:這樣的參數是右值這一事實不會影響隱式轉換序列的排名。 — 尾注 ]

從上面的 /5,以下重載(其中顯式& ref 限定符已被省略)

struct test
{
    test& operator=(const test&) { return *this }
}

允許為 r 值賦值,例如

int main()
{
    test t1;
    t1 = test(); // assign to l-value
    test() = t1; // assign to r-value
}

但是,如果我們使用& ref 限定符顯式聲明重載,則[over.match.funcs]/5.1不適用,並且只要我們不提供使用&& ref 限定符聲明的重載,r 值賦值將不被允許。

struct test
{
    test& operator=(const test&) & { return *this; }
};

int main()
{
    test t1;
    t1 = test(); // assign to l-value
    test() = t1; // error [clang]: error: no viable overloaded '='
}

我不會對在聲明自定義賦值運算符重載時明確包含& ref 限定符是否是“重載operator=的唯一真正方法”發表任何意見,但我敢推測,然后我猜測背后的意圖這樣的聲明是-r-value 賦值的排除。

作為一個正確設計的賦值運算符應該永遠不會是constconst T& operator=(const T&) const &沒有多大意義),並且由於右值不能用於初始化非常量左值引用,一組重載對於僅包含T& operator=(const T&) &的給定類型T ,for operator=永遠不會提供可從標識為右值值類別的T對象調用的可行重載。

根據http://en.cppreference.com/w/cpp/language/member_functions成員函數聲明之后的&lvalue ref-qualifier

換句話說,它要求this是一個值(隱式對象參數具有對 cv 限定的 X 的左值引用類型)。 還有&& ,它要求this是一個 r 值。

從文檔中復制( const-、volatile- 和 ref-qualified 成員函數):

#include <iostream>
struct S {
  void f() & { std::cout << "lvalue\n"; }
  void f() &&{ std::cout << "rvalue\n"; }
};

int main(){
  S s;
  s.f();            // prints "lvalue"
  std::move(s).f(); // prints "rvalue"
  S().f();          // prints "rvalue"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM