C ++ 17 แนะนำตัวแปรอินไลน์
C ++ 17 แก้ไขปัญหานี้สำหรับconstexpr static
ตัวแปรสมาชิกที่ต้องการคำนิยามแบบไม่อยู่ในขอบเขตหากไม่ได้ใช้ ดูครึ่งหลังของคำตอบนี้สำหรับรายละเอียดล่วงหน้า C ++ 17
ข้อเสนอP0386 ตัวแปรอินไลน์แนะนำความสามารถในการใช้ตัวinline
ระบุกับตัวแปร โดยเฉพาะอย่างยิ่งกรณีนี้constexpr
หมายถึงinline
ตัวแปรสมาชิกแบบคงที่ ข้อเสนอบอกว่า:
ตัวระบุแบบอินไลน์สามารถนำไปใช้กับตัวแปรเช่นเดียวกับฟังก์ชั่น ตัวแปรที่ประกาศแบบอินไลน์มีความหมายเช่นเดียวกับฟังก์ชั่นประกาศแบบอินไลน์: มันสามารถกำหนดได้เหมือนกันในหลายหน่วยการแปลจะต้องกำหนดไว้ในทุกหน่วยการแปลที่มีการใช้ odr และพฤติกรรมของโปรแกรมเป็นถ้า มีตัวแปรหนึ่งตัว
และแก้ไข [basic.def] p2:
การประกาศเป็นคำนิยามเว้นแต่
...
- มันประกาศสมาชิกข้อมูลคงที่นอกคำจำกัดความของชั้นเรียนและตัวแปรที่ถูกกำหนดไว้ในชั้นเรียนที่มีตัวระบุ constexpr (การใช้งานนี้ถูกคัดค้าน; ดู [depr.static_constexpr])
...
และเพิ่ม[depr.static_constexpr] :
สำหรับความเข้ากันได้กับมาตรฐานสากล C ++ ก่อนหน้าสมาชิกข้อมูลคงที่ของ constexpr อาจถูกประกาศซ้ำซ้อนนอกคลาสโดยไม่มี initializer การใช้งานนี้เลิกใช้แล้ว [ตัวอย่าง:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
- ตัวอย่างท้าย]
C ++ 14 และก่อนหน้านี้
ใน C ++ 03 เราได้รับอนุญาตเท่านั้นที่จะให้ initializers ในชั้นเรียนสำหรับปริพันธ์ constหรือประเภทการแจงนับ constใน C ++ 11 ใช้constexpr
นี้ก็ขยายไปถึงชนิดที่แท้จริง
ใน C ++ 11 เราไม่จำเป็นต้องให้คำจำกัดความของขอบเขตเนมสเปซสำหรับconstexpr
สมาชิกแบบสแตติกถ้ามันไม่ได้ถูกใช้แล้วเราสามารถดูได้จากส่วนมาตรฐาน C ++ 11 ฉบับร่าง9.4.2
[class.static.data]ซึ่งระบุว่า ( เน้นที่เหมืองไปข้างหน้า ):
[... ] สมาชิกข้อมูลแบบคงที่ของประเภทตัวอักษรสามารถประกาศในคำจำกัดความของชั้นเรียนด้วยตัวระบุ constexpr; ถ้าเป็นเช่นนั้นการประกาศจะต้องระบุวงเล็บปีกกา - หรือ - เท่ากับ - initializer ที่ทุก initializer-clause นั่นคือการมอบหมาย - การแสดงออกคือการแสดงออกคงที่ [หมายเหตุ: ในทั้งสองกรณีนี้สมาชิกอาจปรากฏในนิพจน์คงที่ - บันทึกย่อ]
สมาชิกจะยังคงถูกกำหนดในขอบเขตเนมสเปซถ้าใช้ odr (3.2)ในโปรแกรมและคำจำกัดความขอบเขตเนมสเปซจะต้องไม่มีตัวกำหนดค่าเริ่มต้น
ดังนั้นคำถามจะกลายเป็นbaz
ใช้ไม่ได้ที่นี่:
std::string str(baz);
และคำตอบคือใช่และเราจำเป็นต้องกำหนดขอบเขตเนมสเปซด้วย
แล้วเราจะทราบได้อย่างไรว่าตัวแปรนั้นใช้odrหรือไม่? ถ้อยคำ C ++ 11 ต้นฉบับในส่วน3.2
[basic.def.odr]พูดว่า:
การแสดงออกอาจมีการประเมินเว้นแต่ว่ามันเป็นตัวถูกดำเนินการประเมิน (ข้อ 5) หรือนิพจน์ย่อยของมัน ตัวแปรที่มีชื่อปรากฏเป็นการแสดงออกอาจประเมินเป็น ODR-ใช้จนกว่า
มันเป็นวัตถุที่ตอบสนองความต้องการสำหรับการปรากฏตัวในการแสดงออกคงที่ (5.19) และการแปลง lvalue ไป rvalue (4.1) จะถูกนำไปใช้ทันที
ดังนั้นbaz
การแสดงออกคงที่แต่การแปลง lvalue-to-rvalueไม่ได้ถูกนำมาใช้ทันทีเพราะมันไม่สามารถใช้งานได้เนื่องจากbaz
เป็นอาร์เรย์ สิ่งนี้กล่าวถึงในหมวด4.1
[conv.lval]ซึ่งกล่าวว่า:
glvalue (3.10) ของประเภทที่ไม่ใช่ฟังก์ชั่นที่ไม่ใช่อาร์เรย์ Tสามารถแปลงเป็น prvalue.53 [... ]
สิ่งที่ถูกนำไปใช้ในการแปลงอาร์เรย์ไปชี้
ถ้อยคำของ[basic.def.odr]นี้มีการเปลี่ยนแปลงเนื่องจากรายงานข้อบกพร่อง 712เนื่องจากบางกรณีไม่ได้ครอบคลุมโดยถ้อยคำนี้ แต่การเปลี่ยนแปลงเหล่านี้ไม่ได้เปลี่ยนผลลัพธ์สำหรับกรณีนี้