Hãy xem xét các chương trình đơn giản:Lambda chụp tài liệu tham khảo bằng cách sao chép và decltype
int i = 0;
int& j = i;
auto lambda = [=]{
std::cout << &j << std::endl; //odr-use j
};
Theo [expr.prim.lambda], thành viên đóng cửa biến j
cần phải có loại int
:
Một thực thể là được chụp bằng bản sao nếu được chụp hoàn toàn và chụp mặc định là
=
hoặc nếu được chụp rõ ràng bằng ảnh chụp không có dạng & số nhận dạng hoặc & trình khởi tạo nhận dạng. Đối với mỗi thực thể được chụp bởi bản sao, một thành viên dữ liệu không có tên chưa được đặt tên được khai báo trong loại đóng. Thứ tự khai báo của các thành viên này không được chỉ định. Loại thành viên dữ liệu như vậy là loại đối tượng được ghi tương ứng nếu đối tượng không phải là tham chiếu đến đối tượng, hoặc loại được tham chiếu khác.
Vì vậy, những gì tôi in là địa chỉ của một số int
không liên quan đến bên ngoài phạm vi-i
hoặc j
. Đây là tất cả tốt và tốt. Tuy nhiên, khi tôi ném vào decltype
:
auto lambda = [j] {
std::cout << &j << std::endl;
static_assert(std::is_same<decltype(j), int>::value, "!"); // error: !
};
Đó không biên dịch vì decltype(j)
đánh giá như int&
. Tại sao? j
trong phạm vi đó nên tham khảo thành viên dữ liệu, phải không?
Là một followup liên quan, nếu chụp lambda là thay vì một init-chụp với [j=j]{...}
, sau đó kêu vang sẽ báo cáo decltype(j)
như int
và không int&
. Tại sao sự khác biệt?
bắt đầu bằng '[j = j]' có nghĩa là khoảng 'auto j = j' bên trái' j' không phải là ảnh chụp vì vậy không có gì ngạc nhiên khi nó có ngữ nghĩa khác nhau. init-capture với '[j]' sẽ là tương đương với bạn đang tìm kiếm. – Guvante
"nên tham khảo thành viên dữ liệu". Chỉ khi odr được sử dụng. Nếu không, nó đề cập đến thực thể ban đầu. –