ถูกต้องเพื่อเริ่มต้นอาร์เรย์ในตัวสร้าง constexpr หรือไม่


11

รหัสต่อไปนี้ถูกต้องตามกฎหมายหรือไม่

template <int N>
class foo {
public:
    constexpr foo()
    {
        for (int i = 0; i < N; ++i) {
            v_[i] = i;
        }
    }

private:
    int v_[N];
};

constexpr foo<5> bar;

เสียงดังกังวานยอมรับ แต่ GCC และ MSVC ปฏิเสธมัน

ข้อผิดพลาดของ GCC คือ:

main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
   15 | constexpr foo<5> bar;
      |                  ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
    4 |     constexpr foo()
      |               ^~~
main.cpp:4:15: error: member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor
main.cpp:12:9: note: declared here
   12 |     int v_[N];
      |         ^~

หากรหัสประเภทนี้ตกลงฉันสามารถตัดการใช้งานได้ไม่กี่index_sequenceครั้ง


1
Gcc10ก็ยอมรับเช่นกัน
songyuanyao

คุณสามารถถอดข้อความข้อผิดพลาดจาก MSVC ได้หรือไม่
max66

... และ GCC ด้วย
Evg

1
@songyuanyao - g ++ 10 ยอมรับการคอมไพล์ C ++ 20; ปฏิเสธการรวบรวม C ++ 17 หรือเก่ากว่า จุดดูเหมือนว่า_vควรเริ่มต้นในรายการเริ่มต้นจนถึง C ++ 17 อาจมีการเปลี่ยนแปลงบางอย่างใน C ++ 20
max66

2
@Evg น่าสนใจจริง ๆ เพราะมันอาจจะแนะนำให้ Clang ใช้ "การรับรู้" ของมันว่าวัตถุระยะเวลาคงที่เก็บได้รับ zeroed ออกมาเพื่อพูดว่า "โอเควัตถุนี้อาจได้รับการเริ่มต้นเริ่มต้น แต่อ่านจากintสมาชิกจะไม่พฤติกรรมที่ไม่ได้กำหนด " ฉันสงสัยว่า GCC ไม่ได้ทำตามนั้นหรืออย่างอื่น ...
Lightness Races ใน Orbit

คำตอบ:


13

initialisation เริ่มต้นเล็ก ๆ น้อย ๆ ไม่ได้รับอนุญาตในconstexprบริบทจนกว่า C

เหตุผลที่ฉันคาดเดาก็คือมันเป็นเรื่องง่ายที่จะ "บังเอิญ" อ่านจากการเริ่มต้นดั้งเดิมที่เริ่มต้นการกระทำที่ทำให้โปรแกรมของคุณไม่ได้กำหนดพฤติกรรมและการแสดงออกที่มีพฤติกรรมที่ไม่ได้กำหนดจะถูกห้ามตรงconstexpr( ref ) ภาษาได้รับการขยายแม้ว่าตอนนี้คอมไพเลอร์จะต้องตรวจสอบว่าการอ่านที่เกิดขึ้นและถ้ามันไม่ได้เริ่มต้นเริ่มต้นควรได้รับการยอมรับ มันใช้งานได้มากกว่าคอมไพเลอร์ แต่ (เท่าที่คุณเห็น!) มีประโยชน์มากมายสำหรับโปรแกรมเมอร์

กระดาษนี้เสนอให้อนุญาตการเริ่มต้นเริ่มต้นสำหรับชนิดที่สามารถสร้างได้เริ่มต้นเล็กน้อยในบริบทของ constexpr ในขณะที่ยังคงไม่อนุญาตการเรียกใช้ของพฤติกรรมที่ไม่ได้กำหนด กล่าวโดยย่อตราบใดที่ยังไม่ได้อ่านค่าที่ไม่ใช่ค่าเริ่มต้นสถานะดังกล่าวควรได้รับอนุญาตใน constexpr ในทั้งสถานการณ์ฮีปและสแต็กที่จัดสรร

ตั้งแต่ C ++ 20 เป็นเรื่องถูกกฎหมายที่จะปล่อยให้v_"ไม่มีการกำหนดค่าเริ่มต้น" อย่างที่คุณมี จากนั้นคุณได้กำหนดค่าองค์ประกอบทั้งหมดซึ่งยอดเยี่ยม


4
@ max66 ฉันเหมือนกัน! ทั้งหมดที่ฉันทำคือสแกนรายการเปลี่ยนแปลง C ++ 20 ใน Wikipedia ค้นหาสิ่งที่เกี่ยวข้องconstexprและอ่านข้อเสนอที่เชื่อมโยง;)
Lightness Races ใน Orbit

3
ส่วนที่ไม่ดีคือมากกว่า 20 ปีที่ฉันใช้ C ++ ถ้าทุกวันฉันเรียนรู้สิ่งใหม่ ... หรือฉันเป็นโปรแกรมเมอร์ที่ไม่ดีหรือ C ++ นั้นซับซ้อนเกินไป
max66

5
@ max66 มันเกือบจะแน่นอนหลัง ความจริงที่ว่ามันเปลี่ยนพื้นฐานทุกสองสามปีทำให้มันเป็นเป้าหมายที่รวดเร็ว ใครสามารถติดตามสิ่งนั้นได้! แม้แต่คอมไพเลอร์ก็ยังไม่ทันตามนั้น
การแข่งขัน Lightness ใน Orbit

@ max66 บทความนี้อยู่ในใจ: จดจำ Vasa!
Evg

@Evg โอ้ว้าวกระดาษนั่นผ่านฉันมาด้วย (IRONY) จับได้เห็นชัดตรงเผง!
การแข่งขัน Lightness ใน Orbit
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.