2014-11-07 14 views
5

Biên dịch mã sau với clang 3.5.0 và gcc 4.9.1 mang lại một lỗi ở câu lệnh cuối cùng.Tại sao braced-init-list hoạt động khác trong một cuộc gọi hàm so với lời gọi hàm tạo?

#include <iostream> 

struct Foo { Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; } }; 

void bar(int x, int y) { std::cout << "bar(int = " << x << ", int = " << y << ")" << std::endl; } 

int main() 
{ 
    Foo({}, {}); // Foo(int = 0, int = 0) 
    Foo({1}, {2}); // Foo(int = 1, int = 2) 
    Foo({1, 2}); // Foo(int = 1, int = 2) 

    bar({}, {}); // bar(int = 0, int = 0) 
    bar({1}, {2}); // bar(int = 1, int = 2) 
    bar({1, 2}); // error: no matching function for call to 'bar' <<< Why? <<< 
} 

Tại sao Foo({1, 2}) không sao khi bar({1, 2}) không?

Đặc biệt, thật tuyệt vời khi tìm hiểu về lý do cơ bản.

+3

Tôi đoán là, 'Foo ({1,2})' tạo ra một đối tượng Foo tạm thời và gọi ctor bản sao . – Borgleader

+0

@Borgleader Cảm ơn bạn, điều đó có ý nghĩa! :-) – precarious

+0

Nhận xét của @Borgleader là chính xác - với {1, 2} bạn có thể tạo đối tượng Foo tạm thời, nhưng chỉ khi Foo được mong đợi. Bạn có thể không thực sự vượt qua nhiều tham số để hoạt động với điều đó. –

Trả lời

6

Foo({1,2}) tạo đối tượng Foo tạm thời và gọi hàm tạo bản sao.

Xem ví dụ này được sửa đổi với nhà xây dựng bản sao xóa: http://coliru.stacked-crooked.com/a/6cb80746a8479799

Nó lỗi với:

main.cpp:6:5: note: candidate constructor has been explicitly deleted 
    Foo(const Foo& f) = delete; 
+0

Nhưng không phải là một nhà xây dựng bản sao được tạo ra ngầm trong ví dụ ban đầu? Tại sao xóa nó và gây ra một lý do khác không để biên dịch? Điều này không exaplain tại sao 'bar' không thể được gọi là; và đó là tất cả về các đối số của thanh, xem [cách sửa lỗi biên dịch] này (http://coliru.stacked-crooked.com/a/2b8f6fee6244c251) –

+0

@NorahAttkins Bạn đã bỏ lỡ điểm. Vấn đề là, danh sách initializer không truyền 2 ints tới hàm tạo (mà OP giả định, và tự hỏi tại sao nó không hoạt động trong một cuộc gọi hàm cũng mất 2 int), nó tạo ra một đối tượng tạm thời và gọi copy constructor. Xóa nó cho thấy rằng các nhà xây dựng bản sao đã được gọi. – Borgleader

+0

Không có; Xem [ví dụ này] (http://coliru.stacked-crooked.com/a/7314848093d2987a) Nếu tôi xóa cuộc gọi đến 'Foo ({1, 2})' chương trình vẫn không thể biên dịch khi gọi 'thanh' mà không bao giờ đề cập đến bất cứ điều gì về các nhà xây dựng bản sao đã xóa. Lệnh gọi 'bar' không bao giờ tạo đối tượng' Foo' tạm thời –

1

Dòng

bar({1, 2}); 

thực sự đi vào bar chức năng, một đối tượng tạm thời nhập

<brace-enclosed initializer list> // it's made clear in the comments that brace initializers have no type 

và không có cách nào để chuyển đổi đối tượng tạm thời này thành loại đối số đầu tiên là int. Do đó, error

có thể không chuyển đổi <brace-enclosed initializer list> để int cho lập luận 1 để

void bar(int, int) 
+0

Không, điều đó không đúng. Một braced-init-list không có kiểu. – Columbo

+0

@Columbo Bạn có chắc chắn (http://coliru.stacked-crooked.com/a/7dbfd72283b52c55)? –

+1

@NorahAttkins [Trình khởi tạo nhanh không có loại] (http://www.youtube.com/watch?v=wQxj20X-tIU&list=UUMlGfpWw-RUdWX_JbLCukXg#t=1792) – Borgleader

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