2015-10-12 14 views
9

Câu hỏi của tôi là về phạm vi lambda cho các initializers thành viên tĩnh. Hãy xem xét các thử nghiệm sau đây:phạm vi lambda cho các thành viên tĩnh initializer

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from " << __PRETTY_FUNCTION__ << std::endl; 
}; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 

gcc bắt đầu từ 4.8 định nghĩa các lambda trong phạm vi của S, vì vậy chương trình kết quả đầu ra một cái gì đó như thế này:

Hello from S::<lambda()> 

(gcc-4.8.2 có một định nghĩa khác nhau cho __FUNCTION__ & macro Co, tuy nhiên các lambda vẫn được xác định trong phạm vi S)

trong khi đó gcc-4.7 định nghĩa các lambda trong phạm vi toàn cầu, vì vậy chương trình đầu ra

Hello from <lambda()> 

Có thể gcc mới hơn tuân thủ chuẩn hơn. Tuy nhiên tôi muốn hỏi liệu tiêu chuẩn có thực sự chỉ định khía cạnh này hay không hoặc nó có thể phụ thuộc vào việc triển khai thực hiện.

Cập nhật: vì @ user5434961 đề xuất rằng tất cả các macrođều giống nhau, nên tốt hơn là tránh chúng trong thử nghiệm tuân thủ tiêu chuẩn. Vì vậy, đây là ví dụ mà có thể được biên dịch nếu một trình biên dịch định nghĩa lambdas đó trong thời hạn S phạm vi và phá vỡ biên soạn khác:

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
private: 
    static const int s_field; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from S::s_func. S::s_field = " << S::s_field << std::endl; 
}; 

const int S::s_field = 1; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 
+0

Tôi đoán bạn nên thay đổi 'S :: s_field' thành' s_field' trong ví dụ được cập nhật? Nếu không, tôi nghĩ nó luôn biên dịch bất kể phạm vi là gì. – Lingxi

+0

Vâng, vì 'S :: s_field' là riêng tư, nó không thể được truy cập từ phạm vi toàn cầu nên mã không phá vỡ biên dịch trên GCC-4.7 thực sự – user3159253

+0

Có, có. Tôi bỏ qua những điều riêng tư. – Lingxi

Trả lời

7

Vấn đề này đã được nâng lên trước nhưng tôi không thể tìm thấy báo cáo lỗi có liên quan. Đây là một broken link cho một báo cáo lỗi MSVC được cho là đã đệ trình (nó vẫn chưa được sửa vào năm 2015: bạn có thể kiểm tra nó tại rise4fun). Tuy nhiên nó đã được sửa chữa ở đâu đó giữa 4,7 và 4,8 cho GCC. Các standardese có liên quan sử dụng để sao này lên như là một lỗi là:

[C++ 11, 9.4.2/2] Khái niệm khởi tạo trong định nghĩa fi de của một thành viên static dữ liệu trong phạm vi lớp học .

[C++ 11, 5.1.2/2] Việc đánh giá biểu thức lambda dẫn đến tạm thời giá trị (12.2). Tạm thời này được gọi là đối tượng đóng cửa. Một biểu thức lambda sẽ không xuất hiện trong toán hạng chưa được đánh giá (Điều 5).

[C++ 11, 5.1.2/3] Loại biểu thức lambda (cũng là loại của đối tượng đóng) là loại duy nhất, không công khai loại - được gọi là đóng loại - có thuộc tính được mô tả bên dưới. Loại lớp học này không phải là tổng hợp (8.5.1). Loại đóng được tuyên bố là trong phạm vi khối nhỏ nhất, phạm vi lớp hoặc phạm vi không gian tên chứa biểu thức lambda tương ứng.

Trước

Why lambda in static initializer can't access private members of class in VC++2013?

C++11 lambdas can access my private members. Why?

Why is it not possible to use private method in a lambda?

4

Tôi đoán nó phải ở trong phạm vi lớp học.Trích dẫn từ cppreference (tôi nhấn mạnh):

Biểu thức lambda xây dựng một đối tượng giấu tên prvalue tạm của giấu tên phi công đoàn loại không tổng hợp độc đáo, được gọi là kiểu đóng cửa, được công bố (đối với mục đích của ADL) trong khối nhỏ nhất phạm vi, phạm vi lớp hoặc phạm vi không gian tên có chứa biểu thức lambda .

Trong out-of-line nghĩa về S::s_func, bạn nhập vào phạm vi S thời S:: đang gặp phải. Vì vậy, biểu thức lambda được chứa trong phạm vi lớp của S. Vì loại gần hơn là thành viên của S, quyền truy cập vào các thành viên riêng của S được cấp.

+0

Cảm ơn cả bạn và @ user5434961 vì những câu trả lời hữu ích như nhau. Tôi đã đánh dấu câu trả lời của anh ấy như được chấp nhận vì nó sớm hơn bạn một chút. – user3159253

+0

@ user3159253 Bạn được chào đón :) câu trả lời của người dùng5434961 tốt hơn tôi vì đã trích dẫn tài liệu chuẩn. – Lingxi

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