2017-12-01 26 views
22

Tại sao mã sau không biên dịch theo g ++ (C++ 14), MSVC (C++ 14), hoặc ARM (C++ 03)?Tại sao enum này không chuyển đổi thành int?

Trường hợp Lỗi được đặt tên gọi hàm tạo số nguyên, nhưng cá thể Lỗi ẩn danh không giải quyết được.

class Error 
{ 
public: 
    Error(int err) : code_(err) {} 
    const int code_; 
}; 

enum Value 
{ 
    value_1 
}; 

int main() 
{ 
    // compiles 
    Error e(value_1); 

    // does not compile under G++, ARM, or MSVC 
    Error(value_1); 
} 

Ví dụ lỗi dưới G ++: (Coliru link)

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

main.cpp: In function 'int main()': 
main.cpp:19:18: error: no matching function for call to 'Error::Error()' 
    Error(value_1); 
       ^
main.cpp:4:5: note: candidate: Error::Error(int) 
    Error(int err) : code_(err) {} 
    ^~~~~ 
main.cpp:4:5: note: candidate expects 1 argument, 0 provided 
main.cpp:1:7: note: candidate: constexpr Error::Error(const Error&) 
class Error 
     ^~~~~ 
main.cpp:1:7: note: candidate expects 1 argument, 0 provided 
main.cpp:1:7: note: candidate: constexpr Error::Error(Error&&) 
main.cpp:1:7: note: candidate expects 1 argument, 0 provided 
+1

Chỉnh sửa tiêu đề: có không có ** cast ** trong mã này; câu hỏi là về một ** chuyển đổi **. –

+1

Có thể trùng lặp [Phần nào của tiêu chuẩn C++ cho phép khai báo biến trong dấu ngoặc đơn?] (Https://stackoverflow.com/questions/45991094/which-part-of-the-c-standard-allow-to-declare- biến-trong-dấu ngoặc đơn) –

+0

Nếu không có cả hai bạn chỉ định trình biên dịch đã làm/không hoạt động, báo cáo không thú vị. Nó có thể là một phần mở rộng, nhưng tôi đã không phân tích ngữ pháp. –

Trả lời

33

Điều này xuất phát từ cùng một vị trí với "Cách phân tích cú pháp nhiều nhất" - quy tắc nếu đó có thể là tuyên bố, là tuyên bố.
Và đáng ngạc nhiên, bạn được phép đặt dấu ngoặc đơn quanh mã định danh trong khai báo biến.
(Tôi không có ý tưởng tại sao, nhưng tôi đoán rằng nó đơn giản hóa phân tích cú pháp của C trở lại trong ngày.)

Sau đây là tất cả các tờ khai hợp lệ int biến:

int (foo); 
int (bar) = 0; 
int (baz)(3); 
int (twaddle)(baz); 
+4

Tại sao các dấu ngoặc đơn được phép được giải thích trong K & R. – Ivan

+5

[WP: Phân tích cú pháp gây tranh cãi nhất] (https://en.wikipedia.org/wiki/Most_vexing_parse) – DevSolar

+0

@Ivan Bạn có liên kết/trích dẫn cho phần cụ thể của K & R được đề cập không? – JAB

31

Vấn đề là mã

Error(value_1); 

là một lời tuyên bố của một biến value_1 loại Error.

Đây là di sản từ ngôn ngữ C sử dụng các biểu thức như một phần của khai báo loại.

Ví dụ int *i là con trỏ đến int vì biểu thức đó biểu thị *i nên đánh giá để nhập int. Thêm ví dụ về điều này:

  • int (*func)() là một con trỏ đến hoạt động trở int vì biểu (*func)() đánh giá để gõ int.
  • int *p[8] là một chuỗi con trỏ đến int vì biểu thức *p[x] đánh giá loại int.
  • int (*p)[8] là con trỏ tới mảng 8 int 's (int[8]) vì biểu thức (*p)[x] đánh giá loại int.
  • int (*(*p[8])())() là một mảng gồm 8 con trỏ để hàm trả về con trỏ cho hàm trả về int vì biểu thức (*(*p[x])())() đánh giá loại int.

Tương tự int (i) là một biến đơn giản của kiểu int như biểu (i) đánh giá để gõ int.

Vì vậy, vì C++ kế thừa từ C, nó sử dụng dấu ngoặc đơn như là một phần của khai báo kiểu, nhưng cũng thêm cú pháp trên đầu, dẫn đến một số kết quả không mong muốn.

Quy tắc được áp dụng bởi C++ ở đây nói để xử lý mọi thứ có thể là khai báo dưới dạng khai báo.


nhầm lẫn tương tự nếu thường gây ra bởi mã như thế này:

Error ec(); 

mà là một lời tuyên bố về phía trước của một hàm ec trả Error.

12

main.cpp:19:18: error: no matching function for call to 'Error::Error()'
Error(value_1);

Trình biên dịch sẽ cố gắng để gọi constructor mặc định không tồn tại Error::Error() bởi vì nó thấy

Error(value_1); 

như một khai báo biến

Một tuyên bố được phép có dấu ngoặc không cần thiết.

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