2013-04-06 25 views
20

tôi có mã nàyTrình biên dịch nghĩ rằng "A (A &)" chấp nhận giá trị trong một thời điểm?

struct A { A(); A(A&); }; 
struct B { B(const A&); }; 

void f(A); 
void f(B); 

int main() { 
    f(A()); 
} 

Trước sự ngạc nhiên của tôi này không thành công với GCC và Clang. Clang nói ví dụ

Compilation finished with errors: 
source.cpp:8:10: error: no matching constructor for initialization of 'A' 
     f(A()); 
     ^~~ 
source.cpp:1:21: note: candidate constructor not viable: expects an l-value for 1st argument 
    struct A { A(); A(A&); }; 
        ^
source.cpp:1:16: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    struct A { A(); A(A&); }; 
      ^
source.cpp:4:13: note: passing argument to parameter here 
    void f(A); 

Tại sao họ chọn f đầu tiên, khi lần thứ hai f hoạt động tốt? Nếu tôi xóa f đầu tiên, thì cuộc gọi thành công. Có gì là lạ hơn với tôi, nếu tôi sử dụng cú đúp khởi, nó cũng hoạt động tốt

int main() { 
    f({A()}); 
} 

Tất cả họ đều gọi thứ hai f.

Trả lời

17

Đó là ngôn ngữ quirk. Đầu tiên f phù hợp hơn vì A của bạn không yêu cầu chuyển đổi để phù hợp với loại đối số (A), nhưng khi trình biên dịch cố gắng thực hiện cuộc gọi thực tế là không có trình tạo bản sao phù hợp nào có thể được tìm thấy. Ngôn ngữ không cho phép tính đến tính khả thi của cuộc gọi thực sự được xem xét khi thực hiện bước phân giải quá tải.

gần nhất tiêu chuẩn phù hợp với trích dẫn ISO/IEC 14882: 2011 13.3.3.1.2 trình tự chuyển đổi người dùng định nghĩa [over.ics.user]:

Một chuyển đổi một biểu hiện của kiểu lớp để cùng lớp loại được xếp hạng Đối sánh chính xác và chuyển đổi của biểu thức loại lớp thành lớp cơ sở thuộc loại đó được cấp Thứ hạng chuyển đổi, mặc dù thực tế là một hàm tạo bản sao/di chuyển (tức là hàm chuyển đổi do người dùng xác định) được gọi cho những trường hợp đó.

Đối với trường hợp danh sách khởi tạo, bạn có thể cần phải xem xét: 13.3.3.1.2 trình tự chuyển đổi người dùng định nghĩa [over.ics.user]

Khi đối tượng của lớp không tổng hợp loại T là danh sách khởi tạo (8.5.4), độ phân giải quá tải chọn hàm tạo theo hai pha:

- Ban đầu, hàm ứng cử viên là các hàm tạo danh sách khởi tạo (8.5.4) của lớp T và danh sách đối số bao gồm danh sách trình khởi tạo như một bài hát đối số le.

- Nếu không có constructor khởi tạo danh sách khả thi được tìm thấy, độ phân giải quá tải được thực hiện một lần nữa, nơi chức năng ứng cử viên đều là các nhà thầu của T lớp và danh sách đối số bao gồm các yếu tố của danh sách khởi tạo.

Bởi vì độ phân giải quá tải phải nhìn vào contructors khả thi trong từng trường hợp cho f(A)f(B) nó phải từ chối seqence cố gắng để ràng buộc A() để A(A&) nhưng B(const A&) vẫn còn khả thi.

+0

Cảm ơn! Tôi không thể tìm thấy quy tắc nào cho trường hợp '{...}'. Điều đó có giải thích tại sao trường hợp '{...}' hoạt động không? –

+0

@ JohannesSchaub-litb: Tôi không chắc chắn, tbh, bạn đang gọi hàm với một _braced-init-list_ để các quy tắc chắc chắn khác nhau. –

+0

@ JohannesSchaub-litb Xem [over.ics.list]. Tôi nghĩ rằng phải làm gì với [over.ics.ref]/3 (Tôi đã đọc sai mã của bạn trước đó): Khi tạo thành tập con của các hàm khả thi, ctor 'A (A &)' không được coi là khả thi vì nó liên kết một tham chiếu tạm thời với tham số không phải const. – dyp

Các vấn đề liên quan