ฉันคิดว่าเสียงดังกังวานอาจจะถูกต้องจริง
ตาม[lambda.capture] / 11เป็นรหัสการแสดงออกที่ใช้ในแลมบ์ดาหมายถึงแลมบ์ดาโดยการคัดลอกจับสมาชิกเท่านั้นถ้ามันถือว่าเป็นODR การใช้งาน ถ้ามันไม่ได้แล้วมันหมายถึงนิติบุคคลเดิม สิ่งนี้ใช้ได้กับ C ++ ทุกรุ่นตั้งแต่ C ++ 11
ตามการอ้างอิงพื้นฐานของ C ++ 17 [Basic.dev.odr] / 3ไม่ได้ถูกใช้ถ้าใช้การแปลง lvalue-to-rvalue กับมันทำให้เกิดการแสดงออกอย่างต่อเนื่อง
ในแบบร่าง C ++ 20 อย่างไรก็ตามข้อกำหนดสำหรับการแปลง lvalue-to-rvalue ถูกทิ้งและข้อความที่เกี่ยวข้องเปลี่ยนไปหลายครั้งเพื่อรวมหรือไม่รวมการแปลง ดูCWG ปัญหา 1472และCWG ปัญหา 1741เช่นเดียวกับการเปิดประเด็น CWG 2083
ตั้งแต่m
เริ่มต้นด้วยการแสดงออกอย่างต่อเนื่อง (หมายถึงแบบคงที่ระยะเวลาการเก็บรักษาวัตถุ) ที่ใช้มันมีอัตราผลตอบแทนการแสดงออกอย่างต่อเนื่องต่อข้อยกเว้นใน[expr.const] /2.11.1
นี่ไม่ใช่กรณีอย่างไรก็ตามหากมีการใช้การแปลงแบบ lvalue-to-rvalue เนื่องจากค่าของn
ไม่สามารถใช้งานได้ในนิพจน์คงที่
ดังนั้นขึ้นอยู่กับว่าการแปลงแบบ lvalue-to-rvalue นั้นควรถูกนำไปใช้ในการพิจารณา odr-use หรือไม่เมื่อคุณใช้m
ใน lambda มันอาจจะใช่หรือไม่ใช่สมาชิกของแลมบ์ดา
หากการแปลงควรนำไปใช้ GCC และ MSVC ถูกต้องมิฉะนั้นเสียงดังกราวเป็น
คุณจะเห็นว่าเสียงดังกราวเปลี่ยนพฤติกรรมถ้าคุณเปลี่ยนการเริ่มต้นm
เป็นไม่คงที่อีกต่อไป:
#include <stdio.h>
#include <functional>
int n = 100;
void g() {}
std::function<int()> f()
{
int &m = (g(), n);
return [m] () mutable -> int {
m += 123;
return m;
};
}
int main()
{
int x = n;
int y = f()();
int z = n;
printf("%d %d %d\n", x, y, z);
return 0;
}
ในกรณีนี้คอมไพเลอร์ทั้งหมดยอมรับว่าผลลัพธ์เป็น
100 223 100
เพราะm
ในแลมบ์ดาจะอ้างถึงสมาชิกปิดของซึ่งเป็นประเภทของint
การคัดลอกเริ่มต้นจากตัวแปรอ้างอิงในm
f