เสียงดังกราวถูกต้องหรือไม่ในการปฏิเสธรหัสที่คลาสที่ซ้อนกันของแม่แบบคลาสนั้นถูกกำหนดผ่านความเชี่ยวชาญเฉพาะทางหรือไม่


17

รับแม่แบบชั้นเรียนต่อไปนี้:

template<typename T>
struct Outer
{
    struct Inner;

    auto f(Inner) -> void;
};

เรากำหนดInnerแยกต่างหากสำหรับแต่ละความเชี่ยวชาญของOuter:

template<>
struct Outer<int>::Inner {};

template<>
struct Outer<double>::Inner {};

จากนั้นกำหนดฟังก์ชันสมาชิกfหนึ่งครั้งสำหรับความเชี่ยวชาญพิเศษทั้งหมดของOuter:

auto Outer<T>::f(Inner) -> void
{

}

แต่เสียงดังกราว (9.0.0) บ่น:

error: variable has incomplete type 'Outer::Inner'

auto Outer<T>::f(Inner) -> void

                      ^

เราสามารถหลบเลี่ยงข้อผิดพลาดของคอมไพเลอร์โดยให้คำจำกัดความของInnerความเชี่ยวชาญอื่น ๆ ของOuter:

template<typename T>
struct Outer<T>::Inner {};

หรือโดยการfแยกต่างหากสำหรับแต่ละความเชี่ยวชาญ:

template<>
auto Outer<int>::f(Inner) -> void
{

}

template<>
auto Outer<double>::f(Inner) -> void
{

}

ทั้ง GCC และ MSVC ยอมรับรหัสเริ่มต้นซึ่งทำให้เกิดคำถาม นี่เป็นข้อผิดพลาดของเสียงดังกราวหรือมันเป็นเพียงการนำไปปฏิบัติให้สอดคล้องกับสามข้อเท่านั้น?

ลองใช้ Compiler Explorer


ความเชี่ยวชาญของ Inner ไม่เกี่ยวข้องการลบออกจะไม่เปลี่ยนผลการรวบรวม
n คำสรรพนาม 'm

@ n.'pronouns'm ฉันไม่แน่ใจว่าคุณหมายถึงอะไร ทั้งการเพิ่มคำจำกัดความของInnerความเชี่ยวชาญพิเศษอื่น ๆและการfแยกต่างหากสำหรับแต่ละความเชี่ยวชาญแก้ไขข้อผิดพลาดการรวบรวม
invexed

ลองมาอ่านอีกครั้ง: การลบพวกเขาจะไม่เปลี่ยนแปลงผลการรวบรวม ไม่เพิ่มลบออก gcc clang
n คำสรรพนาม 'm

@ n.'pronouns'm ฉันเห็นสิ่งที่คุณหมายถึงตอนนี้ แต่ยังคงเป็นความคิดเห็นที่แปลกที่จะทำให้ ประเด็นคำถามของฉันInnerคือการรายงานว่าเป็นประเภทที่ไม่สมบูรณ์แม้จะมีคำจำกัดความสำหรับความเชี่ยวชาญเฉพาะด้านของOuterการจัดเตรียม ชัดเจนว่าInnerจะเป็นประเภทที่ไม่สมบูรณ์หากคุณลบคำจำกัดความของมัน
invexed

"Clearly Inner จะเป็นประเภทที่ไม่สมบูรณ์หากคุณลบคำจำกัดความของ" ไม่ว่า "ไม่ ckear เลยความเชี่ยวชาญเป็นแม่แบบที่แยกจากกันอย่างสมบูรณ์และไม่มีผลกับแม่แบบหลักเลย
n. 'คำสรรพนาม'

คำตอบ:


4

ฉันเชื่อว่าเสียงดังกราวผิดที่จะปฏิเสธรหัสของคุณ เราต้องถามตัวเองว่าการประกาศฟังก์ชั่นและคำจำกัดความของคุณเปรียบเทียบได้อย่างไร

auto f(typename T::Inner) -> void;

// ...

template<typename T>
auto Outer<T>::f(typename T::Inner) -> void
{ }

ในตัวอย่างT::Innerนี้เห็นได้ชัดว่าเป็นประเภทที่ต้องพึ่งพา ดังนั้นเสียงดังกังวานอาจไม่ถือว่าสมบูรณ์ ตัวอย่างนี้เป็นจริงหรือไม่? ฉันจะพูดอย่างนั้น สำหรับเรามีสิ่งนี้ในมาตรฐาน:

[temp.dep.type]

5ชื่อเป็นสมาชิกของการสร้างอินสแตนซ์ปัจจุบันถ้าเป็น

  • ชื่อที่ไม่มีเงื่อนไขซึ่งเมื่อค้นหาจะอ้างถึงสมาชิกอย่างน้อยหนึ่งคนของคลาสที่เป็นอินสแตนซ์ปัจจุบันหรือคลาสพื้นฐานที่ไม่ขึ้นอยู่กับมัน [หมายเหตุ: สิ่งนี้สามารถเกิดขึ้นได้เมื่อค้นหาชื่อในขอบเขตที่ล้อมรอบด้วยคำจำกัดความของแม่แบบคลาส - บันทึกท้าย]
  • ...

ชื่อคือ สมาชิกที่ขึ้นต่อกันของการสร้างอินสแตนซ์ปัจจุบันหากเป็นสมาชิกของอินสแตนซ์ปัจจุบันที่เมื่อค้นหาจะอ้างอิงสมาชิกอย่างน้อยหนึ่งสมาชิกของคลาสที่เป็นอินสแตนซ์ปัจจุบัน

9ประเภทขึ้นอยู่กับว่ามันเป็น

  • ...
  • สมาชิกของความเชี่ยวชาญที่ไม่รู้จัก
  • คลาสที่ซ้อนกันหรือการแจงนับซึ่งเป็นสมาชิกที่ขึ้นต่อกันของอินสแตนซ์ปัจจุบัน
  • ...

สัญลักษณ์แสดงหัวข้อแรกในวรรค 9 ครอบคลุมกรณี typename T::Innerครอบคลุมกรณี นั่นคือประเภทที่ขึ้นอยู่กับ

ในขณะที่กรณีของคุณถูกครอบด้วยกระสุนนัดที่สอง Outer::Innerเป็นชื่อที่พบในการสร้างอินสแตนซ์ปัจจุบันOuterนอกจากนั้นจะพบภายในOuterตัวเองไม่ใช่ในคลาสพื้นฐาน ที่ทำให้มันเป็นสมาชิกขึ้นอยู่กับการเริ่มต้นปัจจุบัน ชื่อนี้หมายถึงคลาสที่ซ้อนกัน ซึ่งหมายความว่าเงื่อนไขทั้งหมดในสัญลักษณ์แสดงหัวข้อย่อยที่สองนำไปใช้จึงทำให้Outer::Innerประเภทที่ขึ้นอยู่กับเช่นกัน!

เนื่องจากเรามีประเภทที่ขึ้นต่อกันในทั้งสองกรณีคอมไพเลอร์ควรปฏิบัติต่อพวกเขาอย่างเท่าเทียมกันเป็นประเภทที่ขึ้นต่อกัน ข้อสรุปของฉันคือ GCC และ MSVC นั้นถูกต้อง


Bug รายงาน ขอบคุณ
invexed
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.