2013-05-15 28 views
17

Tôi đang gặp rắc rối với đoạn mã sau:phá vỡ cấu trúc lồng nhau constexpr mặc dù là giống hệt nhau cho những người toàn cầu

template<typename T> 
constexpr int get(T vec) { 
    return vec.get(); 
} 

struct coord { 
    constexpr int get() const { return x; } 
    int x; 
}; 

struct foo { 
    struct coord2 { 
     constexpr int get() const { return x; } 
     int x; 
    }; 
    constexpr static coord f = { 5 }; 
    constexpr static int g = get(f); // works 

    constexpr static coord2 h = { 5 }; 
    constexpr static int i = get(h); // doesn't work 
}; 

constexpr coord foo::f; 
constexpr foo::coord2 foo::h; 

int main(){} 

Về cơ bản, get(f) được coi là một biểu hiện thường xuyên, nhưng không phải là get(h). Điều duy nhất thay đổi là một trong những sử dụng một cấu trúc toàn cầu coord, trong khi khác sử dụng một cấu trúc lồng nhau coord2. Các cấu trúc ' ' của cấu trúc giống hệt nhau.

Tại sao điều này?


GCC lỗi:

test.cpp:20:35: error: field initializer is not constant 

Clang lỗi:

test.cpp:20:26: error: constexpr variable 'i' must be initialized by a constant expression 
    constexpr static int i = get(h); // doesn't work 
         ^ ~~~~~~ 
test.cpp:8:10: note: undefined function 'get' cannot be used in a constant expression 
    return vec.get(); 
     ^
test.cpp:20:30: note: in call to 'get({5})' 
    constexpr static int i = get(h); // doesn't work 
          ^
test.cpp:13:21: note: declared here 
     constexpr int get() const { return x; } 

Trả lời

17

Nó là một biểu thức hằng .... cuối cùng, vì điều này cho thấy bạn có thể nhìn thấy bằng cách di chuyển i vào main():

Các thông báo lỗi là khá rõ ràng những gì đang xảy ra, đó là foo::coord2::get() không được định nghĩa nào, vì các định nghĩa hàm thành viên được trì hoãn cho đến khi kết thúc lớp học kèm theo để họ có thể sử dụng các thành viên tuyên bố sau đó.

Có một chút ngạc nhiên khi định nghĩa bị trễ cho đến khi kết thúc lớp ngoài cùng, nhưng bạn thậm chí còn ngạc nhiên hơn nếu foo::coord2::get() không thể truy cập foo::g.

Tiêu chuẩn đồng ý với trình biên dịch, btw. Một phần của phần 9.2p2 nói

Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes).

Thật không may, chỉ phỏng đoán rằng dấu ngoặc đóng của khai báo lớp sẽ trở thành điểm định nghĩa cho các khu vực trì hoãn này. Tôi tin rằng đó là một khiếm khuyết trong tiêu chuẩn mà nó không nói điều này một cách rõ ràng.

Xem thêm:

+0

@dyp: Đó không phải là những gì tôi nói? (Nó được suy ra, nó không phải là rõ ràng) –

+0

Ah, OK, tôi hiểu lầm đoạn đó, xin lỗi. – dyp

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