ตัวดำเนินการความเท่าเทียมกันไม่ได้ถูกกำหนดไว้สำหรับการใช้งานยานอวกาศที่กำหนดเองใน C ++ 20


51

ฉันพบพฤติกรรมแปลก ๆ กับผู้ประกอบการยานอวกาศใหม่<=>ใน C ++ 20 ฉันใช้ Visual Studio 2019 /std:c++latestกับคอมไพเลอร์

รหัสนี้คอมไพล์ได้ดีตามที่คาดไว้:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}

อย่างไรก็ตามหากฉันเปลี่ยนXเป็นสิ่งนี้:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};

ฉันได้รับข้อผิดพลาดของคอมไพเลอร์ต่อไปนี้:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

ฉันลองทำเสียงดังกราวเช่นกันและฉันก็มีพฤติกรรมที่คล้ายกัน

ฉันขอขอบคุณคำอธิบายบางอย่างเกี่ยวกับสาเหตุที่การใช้งานเริ่มต้นสร้างขึ้นoperator==อย่างถูกต้อง แต่การกำหนดเองไม่ได้

คำตอบ:


50

นี่คือโดยการออกแบบ

[class.compare.default] (เน้นที่เหมือง)

3หากคำจำกัดความของคลาสไม่ได้ประกาศ== ฟังก์ชันตัวดำเนินการอย่างชัดเจนแต่จะประกาศฟังก์ชันตัวดำเนินการเปรียบเทียบสามทางที่เป็นค่าเริ่มต้น==ฟังก์ชันตัวดำเนินการจะถูกประกาศโดยปริยายด้วยการเข้าถึงแบบเดียวกับฟังก์ชันตัวดำเนินการเปรียบเทียบสามทาง ==โอเปอเรเตอร์ที่ประกาศโดยปริยายสำหรับคลาส X เป็นสมาชิกอินไลน์และกำหนดเป็นค่าเริ่มต้นในคำจำกัดความของ X

เพียงผิดนัด<=>ช่วยสังเคราะห์==จะมีชีวิตอยู่ เหตุผลคือคลาสที่ชอบstd::vectorไม่สามารถใช้ค่า<=>เริ่มต้นได้ นอกจากนี้การใช้<=>เพื่อ==ไม่ใช่วิธีที่มีประสิทธิภาพที่สุดในการเปรียบเทียบเวกเตอร์ <=>จะต้องให้คำสั่งที่แน่นอนในขณะที่==อาจประกันตัวในช่วงต้นโดยการเปรียบเทียบขนาดก่อน

หากชั้นเรียนทำสิ่งที่พิเศษในการเปรียบเทียบสามทางมันอาจจะต้องทำสิ่งพิเศษในชั้น==เรียน ดังนั้นแทนที่จะสร้างค่าเริ่มต้นที่ไม่สมเหตุสมผลภาษาปล่อยให้เป็นโปรแกรมเมอร์


4
มันสมเหตุสมผลอย่างแน่นอนเว้นแต่ยานอวกาศจะเป็นรถ อาจเกิดการผิด แต่ไม่มีประสิทธิภาพ ...
Deduplicator

1
@Deduplicator - ความรู้สึกเป็นเรื่องส่วนตัว บางคนบอกว่าการใช้งานที่ไม่มีประสิทธิภาพอย่างเงียบ ๆ นั้นไม่สมเหตุสมผล
StoryTeller - Unslander Monica

45

ในระหว่างการทำให้เป็นมาตรฐานของคุณลักษณะนี้มีการตัดสินใจว่าความเท่าเทียมกันและการสั่งซื้อควรแยกออกจากกันอย่างมีเหตุผล เช่นการใช้ประโยชน์จากการทดสอบความเท่าเทียมกัน ( ==และ!=) จะไม่เคยoperator<=>วิงวอน อย่างไรก็ตามมันก็ยังเห็นว่ามีประโยชน์ที่จะสามารถเริ่มต้นทั้งสองด้วยการประกาศเดียว ดังนั้นหากคุณกำหนดค่าเริ่มต้นoperator<=>จะมีการตัดสินใจว่าคุณควรตั้งค่าเริ่มต้นด้วยoperator==(เว้นแต่คุณจะกำหนดไว้ในภายหลังหรือกำหนดไว้ก่อนหน้านี้)

สำหรับเหตุผลที่ทำให้การตัดสินใจครั้งนี้การใช้เหตุผลขั้นพื้นฐานเป็นเช่นนี้ std::stringพิจารณา การเรียงลำดับของสองสายคือการทำพจนานุกรม อักขระแต่ละตัวมีค่าจำนวนเต็มเปรียบเทียบกับอักขระแต่ละตัวในสตริงอื่น ความไม่เท่าเทียมครั้งแรกส่งผลให้เกิดผลลัพธ์ของการสั่งซื้อ

อย่างไรก็ตามการทดสอบความเท่าเทียมกันของสายมีการลัดวงจร หากทั้งสองสายไม่ได้มีความยาวเท่ากันก็ไม่มีเหตุผลที่จะเปรียบเทียบตัวละครที่ฉลาด พวกเขาไม่เท่ากัน ดังนั้นหากใครบางคนทำการทดสอบความเท่าเทียมกันคุณไม่ต้องการทำแบบยาวถ้าคุณสามารถลัดวงจรได้

ปรากฎว่ามีหลายประเภทที่ต้องการการสั่งซื้อที่ผู้ใช้กำหนดจะเสนอกลไกการลัดวงจรสำหรับการทดสอบความเท่าเทียมกัน เพื่อป้องกันไม่ให้ผู้คนนำไปใช้เท่านั้นoperator<=>และละทิ้งประสิทธิภาพที่มีศักยภาพเราจึงบังคับให้ทุกคนทำอย่างมีประสิทธิภาพ


5
นี่คือคำอธิบายที่ดีกว่าได้รับการยอมรับคำตอบ
บันทึก

17

คำตอบอื่น ๆ อธิบายได้ดีมากว่าทำไมภาษาเป็นเช่นนี้ ฉันแค่อยากจะเพิ่มสิ่งนั้นในกรณีที่ไม่ชัดเจนมันเป็นไปได้ที่จะมีผู้ใช้ที่operator<=>มีค่าoperator==เริ่มต้น คุณเพียงแค่ต้องเขียนค่าเริ่มต้นอย่างชัดเจนoperator==:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.