2015-01-19 23 views
8

Gần đây tôi gặp phải một vấn đề mà bằng cách nào đó (nhưng chỉ bằng cách nào đó) có ý nghĩa với tôi. Nó được dựa trên việc giải thích việc xây dựng tạm thời như là khai báo đối số hàm tạo đơn (!). Vui lòng xem ví dụ tối thiểu bên dưới.Xây dựng tạm thời trong cuộc gọi chức năng được hiểu là khai báo

#include <iostream> 

class Foo0{ 
public: 
    Foo0(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Foo1{ 
public: 
    Foo1(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Foo2{ 
public: 
    Foo2(int a){}; 
    void doStuff() {std::cout<<"maap"<<std::endl;}; 
}; 

class Bar{ 
public: 
    Bar(Foo0 foo0, Foo1 foo1, Foo2 foo2){}; 
}; 

int main() { 
    int x = 1; 

    Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’ 
    Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF 
    Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF 
    Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’ 
    Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me 

    x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious though. 
} 

Tôi đã đọc cuốn sách biểu như:

Foo(a); 

đang giải thích (nếu có một nhà xây dựng tiêu chuẩn) như lời tuyên bố của một. Điều này làm cho tinh thần và nó là hoàn toàn tốt, vì bạn chỉ có thể sử dụng {} -brackets để làm cho việc xây dựng rõ ràng. Nhưng những gì tôi không hiểu là:

  1. Tại sao có vấn đề với việc xây dựng bar0? Tất cả Foo s không có hàm tạo tiêu chuẩn. Vì vậy, nó không có ý nghĩa để giải thích một cái gì đó như Foo0(x) như tuyên bố của x.

  2. Tại sao việc xây dựng các công trình bar1bar2 hoạt động? Rõ ràng với tôi rằng việc xây dựng bar4 hoạt động, vì tôi sử dụng {} -brackets cho tất cả các tạm thời Foo s, do đó tôi rõ ràng về những gì tôi muốn.

  3. Nếu chỉ cần sử dụng {} -brackets chỉ với một trong số Foo s để giải quyết vấn đề ... tại sao việc xây dựng bar3 không thành công?

  4. Ngoài ra, x được khai báo trước khi bất kỳ Thanh nào được tạo. Tại sao trình biên dịch không phàn nàn về điều đó?

Câu hỏi cuối cùng liên quan đến dòng mã mẫu cuối cùng của tôi. Câu chuyện dài ngắn: Trình biên dịch nghĩ rằng tôi muốn anh ấy làm gì và tôi bỏ lỡ sự xuất hiện của bóng tối ở đâu?

PS: Nếu nó quan tâm - tôi sử dụng gcc-4.9.2.
PPS: Tôi đã thử cùng với hàm tạo của bar lấy ba đối số Foo0 s làm đối số. Cùng câu chuyện ở đây. Nhưng lỗi này không nói gì về việc khai báo mâu thuẫn nhưng về định nghĩa lại x.

+1

Để bạn biết, 'bar0' là khai báo hàm có ba' Foo 'và trả về một' Foo', nó không phải là một đối tượng 'Foo'. Ngoài ra, thực tế là việc khai báo 'bar3' không hoạt động là một lỗi trong bất kỳ trình biên dịch nào bạn đang sử dụng. Dòng đó sẽ hoạt động như trong [clang] (http://coliru.stacked-crooked.com/a/d5f8305eff385830). – 0x499602D2

+0

@ 0x499602D2 đã báo lỗi cho tôi bằng g ++ 4.8.1 –

+0

Chỉ cần chính xác: 'bar0' là khai báo hàm có ba' Foo 'và trả về' Thanh '. – sedriel

Trả lời

10

Quy tắc là nếu khai báo có cú pháp của khai báo hàm thì đó là một khai báo; nếu không nó là một tuyên bố biến. Các trường hợp ngạc nhiên về điều này đôi khi được gọi là .

Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’ 

Đây là một khai báo hàm: bar0 là tên, Bar là kiểu trả về, và các loại tham số là Foo0, Foo1Foo2. Các tên tham số là tất cả x là bất hợp pháp - tên của các tham số hàm phải khác nhau. Nếu bạn thay đổi xxx đến xyz lỗi sẽ biến mất).

Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF 
Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF 
Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me 

Những dòng này và tạo các đối tượng bar1, bar2, và bar4 loại Bar. Chúng không thể được phân tích cú pháp dưới dạng khai báo hàm do ký hiệu { } không phải là cú pháp hợp lệ trong khai báo hàm.

Do đó, Foo0{x} vv là các biểu thức cung cấp các đối số cho hàm tạo của Bar. Foo0{x}Foo0(x) là các cách tương đương để khai báo tạm thời loại Foo0 với công cụ khởi tạo x.

Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’ 

Tôi nghĩ đây là lỗi trình biên dịch; phần Foo2{x} có nghĩa là dòng này không thể là khai báo hàm; và có vẻ như một tuyên bố hợp lệ của biến số bar3.

x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious 

xint; nó không có bất kỳ phương pháp nào.

+0

Bar0 là khai báo chức năng hợp pháp như thế nào? 'Type (name)' có nghĩa là gì trong ngữ cảnh đó? Nó chỉ là ràng buộc/nhóm, như 'int (* foo)' - vì vậy 'type (name)' là giống như 'type name'? Tôi đã thực sự bắt đầu như C + + ở lần. – JasonN

+0

@JasonN [xem tại đây] (http://stackoverflow.com/questions/21624880/how-does-this-declaration-invoke-the-most-vexing-parse) để có giải thích tốt –

+0

Cảm ơn. Awesomeness của phân tích phức tạp. '-Wvexing-parse' thật buồn cười. Buồn cùng một lúc. – JasonN

2

1) Foo0 (x) được coi là tham số của hàm bar0 trong trường hợp này. Ở đây, nó không quan trọng nếu nó có một constructor tiêu chuẩn hay không. Nó không phải là một khai báo biến cục bộ và khởi tạo, mà chỉ là khai báo tham số trong khai báo hàm.

2) Đoán của tôi là việc này có liên quan đến phân tích cú pháp, nhưng ai đó sửa tôi nếu tôi sai. Ví dụ bar1 và bar2 hoạt động, vì trình biên dịch biết rằng bar1 và bar2 là khai báo biến cục bộ (chứ không phải khai báo hàm) ngay sau khi nó thấy sự xuất hiện đầu tiên của {}. Những lần xuất hiện đầu tiên {} xuất hiện trước x được khai báo hai lần như một tham số của hàm.

3) Việc xây dựng bar3 không thành công, vì trình biên dịch đầu tiên giả định rằng bar3 là khai báo hàm. Khai báo hàm có ba tham số, tất cả được đặt tên là x. Rõ ràng, điều này là không chính xác.

4) Dấu x trong khai báo hàm chỉ là tên cho tham số. Nó nằm trong một phạm vi khác với số nguyên x bạn đã khai báo trước đó.

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