ทำ Derived1 :: ฐานและ Derived2 :: ฐานอ้างถึงชนิดเดียวกันหรือไม่


12

MSVC, Clang และ GCC ไม่เห็นด้วยกับรหัสนี้:

struct Base { int x; };
struct Der1 : public  Base {};
struct Der2 : public  Base {};

struct AllDer : public Der1, public Der2 {
    void foo() {
        Der1::Base::x = 5;
    }
};

Godbolt

GCC:

<source>: In member function 'void AllDer::foo()':    
<source>:10:21: error: 'Base' is an ambiguous base of 'AllDer'    
   10 |         Der1::Base::x = 5;    
      |                     ^    
Compiler returned: 1

เสียงดังกราวให้ข้อผิดพลาดที่คล้ายกันและ MSVC ให้ไม่มีข้อผิดพลาด

ใครอยู่ที่นี่

ฉันคิดว่านี่จะครอบคลุมใน[class.member.lookup]แต่ฉันมีปัญหาในการเข้าใจสิ่งที่พยายามบอกฉันสำหรับกรณีนี้ กรุณาพูดส่วนที่เกี่ยวข้องและถ้าเป็นไปได้อธิบายเป็นภาษาอังกฤษธรรมดา

PS: แรงบันดาลใจจากคำถามนี้ทำไมอ้างอิงถึงคลาสฐานที่ไม่ชัดเจนกับ :: -operator รางมาระดับ?

PPS: อันที่จริงข้อสงสัยของฉันคือว่าDer1::Baseหมายถึงประเภทที่จะBase(และจากนั้นDer2::Baseเป็นประเภทเดียวกัน) หรือ subobject ฉันเชื่อว่ามันเป็นครั้งแรก แต่ถ้าเป็นหลัง MSVC จะถูกต้อง



@LanguageLawyer คำแนะนำที่ดีมาก ๆ ว่า gcc และ clang นั้นถูกต้อง แต่ฉันไม่มั่นใจอย่างเต็มที่ว่า mscv นั้นผิด
idclev 463035818

1
เห็นได้ชัดว่าทั้งสองอ้างถึงประเภทเดียวกัน::Baseแต่คำถามจริงดูเหมือนจะแตกต่างกันเล็กน้อยที่นี่ มี subobjects สองประเภทBaseและทั้งสองมีBase::x สมาชิก
MSalters

@ พูดถึง PPS เพียงแค่แสดงความสับสนของฉัน หากคุณมีข้อเสนอแนะสำหรับชื่อที่ดีกว่าอย่าลังเลที่จะแก้ไขฉันไม่ชอบตัวเอง (เพราะฉันรู้ว่าคำตอบคือใช่) แต่ไม่พบสิ่งที่เหมาะสมกว่า
idclev 463035818

1
@ d4rk4ng31 ไม่มีมรดกเสมือนในรหัส (โดยเจตนา)
idclev 463035818

คำตอบ:


6

ในการตอบคำถามในชื่อใช่ให้Derived1::Baseอ้างอิงinjected-class-name [class.pre] Baseและอื่นDerived2::Base::Baseทั้งสองอ้างในชั้นเรียน

ตอนนี้ถ้าBaseจะมีสมาชิกคงที่xแล้วการค้นหาBase::xจะไม่ชัดเจน มีเพียงหนึ่งเดียว

ปัญหาในตัวอย่างนี้คือสมาชิกที่xไม่คงที่และAllDerมีสมาชิกดังกล่าวสองราย คุณสามารถยกเลิกการเข้าถึงดังกล่าวได้xโดยการระบุคลาสพื้นฐานที่ชัดเจนAllDerซึ่งมีxสมาชิกเพียงคนเดียว Derived1เป็นคลาสพื้นฐานที่ไม่คลุมเครือและมีxสมาชิกหนึ่งคนดังนั้นDerived1::xระบุได้อย่างชัดเจนว่าxสมาชิกคนใดในสองAllDerคุณหมายความว่าอย่างไร Baseก็มีเพียงหนึ่งxสมาชิก AllDerแต่มันไม่ได้เป็นฐานที่ชัดเจนของ ตัวอย่างของทุกคนมีสองย่อยวัตถุชนิดAllDer Baseดังนั้นจึงBase::xไม่ชัดเจนในตัวอย่างของคุณ และเนื่องจากDerived1::Baseเป็นเพียงชื่ออื่นสำหรับBaseสิ่งนี้ยังคงคลุมเครือ

[class.member.lookup] ระบุว่าxจะค้นหาในบริบทของ nested-name-specifier ดังนั้นจึงต้องแก้ไขก่อน เรากำลังมองหาแน่นอนBase::xไม่ได้Derived1::xเพราะเราเริ่มต้นโดยการแก้ไขเป็นDerived1::Base Baseส่วนนี้สำเร็จมีเพียงหนึ่งxในBase.หมายเหตุ 12 ใน [class.member.lookup] บอกคุณอย่างชัดเจนว่าการใช้การค้นหาชื่อที่ไม่คลุมเครืออาจยังคงล้มเหลวเมื่อมีหลาย subobjects ที่มีชื่อเดียวกัน ในตัวอย่างที่เป็นพื้นของคุณD::iBase::x


ดังนั้น "เท่านั้นอาจล้มเหลว" แต่ไม่ใช่ "ต้องล้มเหลว" และคอมไพเลอร์ทั้งสามนั้นถูกต้องใช่ไหม พิจารณาเช่นtemplate <typname A,typename B> struct foo : A,Bมีรหัสที่วางแผนบางอย่างให้กับสมาชิกในการเข้าถึงฐานของและA Bในกรณีเช่นนี้ฉันต้องการได้รับข้อผิดพลาด
idclev 463035818

1
@ idclev463035818: ผมสงสัยว่ามันเป็น "ต้องล้มเหลว" การวินิจฉัยที่จำเป็น โดยเฉพาะอย่างยิ่งสิ่งนี้ล้มเหลวในการเข้าถึงสมาชิกระดับ 7.6.1.4/7 "รูปแบบไม่ดี"
MSalters

ฉันต้องอ่านเพิ่มอีกนิด และฉันจะต้องทำการวิจัยเกี่ยวกับ msvc ฉันสงสัยว่าธงบางอย่างจำเป็นต้องใช้เพื่อให้ได้ผลลัพธ์เต็มรูปแบบ แต่ต้องค้นหาว่าธงใด
idclev 463035818

2

เหตุผลที่คุณสามารถอ้างถึงชื่อคลาสในฐานะสมาชิกของคลาสเป็นเพราะ cpp แทนนามแฝงเพื่อความสะดวกในการใช้งานราวกับว่าคุณเขียนไว้using Base = ::Base;ในฐาน
ปัญหาที่คุณกำลังเผชิญก็คือว่าเป็นDer1::Base ดังนั้นเมื่อคุณเขียนก็เช่นเดียวกับ Base
Der1::Base::xBase::x


ฉันรู้ว่า "ปัญหา" คืออะไร แต่คุณไม่ได้ตอบคำถามของฉัน: "ใครเป็นใคร (และทำไม?)"
idclev 463035818

@ idclev463035818: ฉันเชื่อว่านี่เป็นด้านขวา ส่วนที่เกี่ยวกับการusingเขียนในมาตรฐานและฉันคิดว่านั่นคือกุญแจสำคัญในการตีความสิ่งที่แสดงออกว่า
Dani

@ idclev463035818: ดูตัวอย่างต่อไปนี้ ฉันคิดว่ามันจะชัดเจนขึ้นเล็กน้อย ideone.com/IqpXjT
Dani

ขอโทษ แต่ฉันคิดว่าคุณไม่เข้าใจคำถามของฉัน ฉันอยากรู้ว่าอะไรถูกต้องตามมาตรฐานเพราะฉันเห็นคอมไพเลอร์ต่างกันทำสิ่งต่าง ๆ การดูว่าคอมไพเลอร์ตัวใดตัวหนึ่งทำอะไรกับตัวอย่างตัวใดตัวหนึ่งไม่ช่วยตอบคำถาม
idclev 463035818

เพียง FYI, MSVC (เวอร์ชั่น 19.25.28614 สำหรับ x64) ล้มเหลวในการรวบรวมตัวอย่างของคุณที่ideone.com/IqpXjT ใช้cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cppเป็นบรรทัดคำสั่งของฉันได้รับmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'
heap underrun
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.