Tại sao sự quá tải này của một toán tử chuyển đổi được chọn?


27

Hãy xem xét các mã sau đây .

struct any
{
    template <typename T>
    operator T &&() const;

    template <typename T>
    operator T &() const;
};
int main()
{
    int a = any{};
}

Ở đây toán tử chuyển đổi thứ hai được chọn bởi độ phân giải quá tải. Tại sao?

Theo như tôi hiểu, hai toán tử được suy ra operator int &&() constoperator int &() consttương ứng. Cả hai đều nằm trong tập hợp các chức năng khả thi. Đọc qua [over.match.best] không giúp tôi tìm ra lý do tại sao cái sau tốt hơn.

Tại sao chức năng sau tốt hơn chức năng trước?


Tôi là một con mèo đơn giản và tôi muốn nói nó phải là lần thứ hai một lần nữa, việc giới thiệu con khác sẽ là một sự thay đổi đột phá trong C ++ 11. Nó sẽ ở trong tiêu chuẩn ở đâu đó. Câu hỏi hay, có một upvote. (Các chuyên gia chú ý: nếu bình luận này là hogwash thì xin vui lòng cho tôi biết!)
Bathsheba

3
FWIW, template <typename T> operator T &&() const &&; template <typename T> operator T &() const &;hãy gọi nó đầu tiên.
NathanOliver

5
@LightnessRaceswithMonica Toán tử chuyển đổi cho phép nếu không sẽ không có cách nào để có nhiều toán tử chuyển đổi.
NathanOliver

1
@Bathsheba Tôi không nghĩ đó là lý do tại sao. Điều đó giống như nói rằng các nhà xây dựng di chuyển không bao giờ có thể được chọn bởi độ phân giải quá tải bởi vì nó sẽ là một thay đổi đột phá. Nếu bạn viết một hàm tạo di chuyển, bạn sẽ chọn mã của mình bị "hỏng" theo định nghĩa đó.
Brian

1
@LightnessRaceswithMonica Cách tôi giữ thẳng trong đầu là tôi coi kiểu trả về là tên của hàm. Các loại khác nhau bằng các tên khác nhau tương đương với thành công :)
NathanOliver

Câu trả lời:


13

Toán tử chuyển đổi trả về T&được ưa thích vì nó chuyên biệt hơn toán tử chuyển đổi trả về T&&.

Xem C ++ 17 [temp.deduct.partial] / (3.2):

Trong ngữ cảnh của lệnh gọi hàm chuyển đổi, các kiểu trả về của các mẫu hàm chuyển đổi được sử dụng.

và / 9:

Nếu, đối với một loại nhất định, khấu trừ thành công theo cả hai hướng (nghĩa là các loại giống hệt nhau sau các biến đổi ở trên) và cả hai PAlà loại tham chiếu (trước khi được thay thế bằng loại được đề cập ở trên): - nếu loại từ mẫu đối số là một tham chiếu lvalue và kiểu từ mẫu tham số thì không, kiểu tham số không được coi là ít nhất là chuyên biệt như kiểu đối số; ...


12

Các toán tử chuyển đổi giá trị trả về được suy ra là một chút lạ. Nhưng ý tưởng cốt lõi là nó hoạt động như một tham số chức năng để chọn cái nào được sử dụng.

Và khi quyết định giữa T&&T&các T&chiến thắng trong các quy tắc giải quyết tình trạng quá tải. Đây là để cho phép:

template<class T>
void f( T&& ) { std::cout << "rvalue"; }
template<class T>
void f( T& ) { std::cout << "lvalue"; }

làm việc. T&&có thể phù hợp với một giá trị, nhưng khi cả hai giá trị quá tải tham chiếu phổ biến và giá trị đều có sẵn, thì giá trị lvalue được ưu tiên.

Tập hợp đúng của các toán tử chuyển đổi có thể là:

template <typename T>
operator T&&() &&;

template <typename T>
operator T &() const; // maybe &

hoặc thậm chí

template <typename T>
operator T() &&;

template <typename T>
operator T &() const; // maybe &

để ngăn chặn sự mở rộng suốt đời không cắn bạn.

3 Các loại được sử dụng để xác định thứ tự phụ thuộc vào ngữ cảnh trong đó việc đặt hàng một phần được thực hiện:

[SNIP]

(3.2) Trong ngữ cảnh của lệnh gọi hàm chuyển đổi, các kiểu trả về của các mẫu hàm chuyển đổi được sử dụng.

Mà sau đó kết thúc tùy thuộc vào quy tắc "chuyên biệt hơn" khi chọn quá tải:

(9.1) nếu loại từ mẫu đối số là tham chiếu giá trị và loại từ mẫu tham số thì không, loại tham số không được coi là ít nhất là chuyên biệt như loại đối số; nếu không thì,

Do đó, operator T&&ít nhất là không chuyên biệt như operator T&trong khi đó, không có trạng thái quy tắc nào operator T&ít nhất là chuyên biệt như operator T&&vậy, vì vậy operator T&nó chuyên biệt hơn operator T&&.

Các mẫu chuyên dụng hơn giành được độ phân giải quá tải hơn ít hơn, mọi thứ khác đều bằng nhau.


Ai đó đã thêm thẻ luật sư ngôn ngữ khi tôi đang trả lời; Tôi chỉ có thể xóa. Tôi có một trí nhớ mơ hồ khi đọc văn bản nói rằng nó được coi là một tham số để chọn cái nào được gọi và văn bản nói về cách xử lý &&vs &khi chọn quá tải mẫu, nhưng việc trêu chọc văn bản chính xác sẽ mất một lúc .
Yakk - Adam Nevraumont

4

Chúng tôi đang cố gắng khởi tạo một inttừ any. Quá trình cho nó:

  1. Chỉ ra tất cả các cách chúng ta có thể làm điều đó. Đó là, xác định tất cả các ứng cử viên của chúng tôi. Chúng đến từ các hàm chuyển đổi không rõ ràng có thể được chuyển đổi intthông qua chuỗi chuyển đổi tiêu chuẩn ( [over.match.conv] ). Phần chứa cụm từ này:

    Một cuộc gọi đến một chức năng chuyển đổi trả về tham chiếu của mối quan hệ với nhau Xlà một loại giá trị Xvà do đó, một chức năng chuyển đổi như vậy được coi là mang lại hiệu quả Xcho quá trình lựa chọn các chức năng ứng cử viên này.

  2. Chọn ứng viên tốt nhất.

Sau bước 1, chúng tôi có hai ứng cử viên. operator int&() constoperator int&&() const, cả hai đều được coi là mang lại intcho mục đích lựa chọn chức năng ứng cử viên. Đó là ứng cử viên tốt nhất cho năng suất int?

Chúng tôi có một máy bẻ khóa ưu tiên các tham chiếu lvalue cho các tham chiếu rvalue ( [over.ics.rank] /3.2.3 ). Mặc dù vậy, chúng tôi không thực sự ràng buộc một tham chiếu ở đây và ví dụ có phần đảo ngược - đây là trường hợp tham số là tham chiếu lvalue so với rvalue.

Nếu điều đó không áp dụng, thì chúng ta sẽ chuyển sang bộ bẻ khóa [over.match.best] /2,5 thích sử dụng mẫu hàm chuyên dụng hơn.

Nói chung, quy tắc của ngón tay cái là chuyển đổi cụ thể hơn là phù hợp nhất. Hàm chuyển đổi tham chiếu lvalue cụ thể hơn hàm chuyển đổi tham chiếu chuyển tiếp, vì vậy nó được ưu tiên. Không có gì về việc intchúng tôi đang khởi tạo yêu cầu một giá trị (thay vào đó chúng tôi đã khởi tạo một int&&, sau đó operator T&() constsẽ không phải là một ứng cử viên).


3.2.3 thực sự nói T&&thắng không? À, nhưng chúng ta không có một giá trị nào bị ràng buộc. Hay chúng ta? Khi chọn ứng viên của chúng tôi, một số từ phải xác định cách chúng tôi có int&và đó có phải int&&là một ràng buộc không?
Yakk - Adam Nevraumont

@ Yakk-AdamNevraumont Không, người ta thích các tham chiếu giá trị hơn các tham chiếu giá trị. Tôi nghĩ dù sao đó cũng có thể là phần sai, và bộ bẻ khóa "chuyên dụng hơn" là phần chính xác.
Barry
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.