ตัวดำเนินการ <=> ใน C ++ คืออะไร


215

ขณะที่ผมกำลังพยายามที่จะเรียนรู้เกี่ยวกับภาษา C ++ผู้ประกอบการที่ฉัน stumbled เมื่อดำเนินการเปรียบเทียบที่ผิดปกติในcppreference.com , *ในตารางที่มองเช่นนี้:

ป้อนคำอธิบายรูปภาพที่นี่

"เอาล่ะถ้านี่เป็นโอเปอเรเตอร์ทั่วไปใน C ++ ฉันควรจะเรียนรู้" แต่ความพยายามทั้งหมดของฉันที่จะอธิบายความลึกลับนี้ไม่ประสบความสำเร็จ แม้แต่ที่นี่ใน Stack Overflow ฉันไม่มีโชคในการค้นหาของฉัน

มีการเชื่อมต่อระหว่าง<=>และC ++หรือไม่

และถ้ามีตัวดำเนินการนี้ทำอะไรกันแน่

* ในระหว่างนี้ cppreference.com ได้อัพเดตหน้านั้นและตอนนี้มีข้อมูลเกี่ยวกับ<=>ผู้ให้บริการ


82
@haccks: โอ้ได้โปรดเรามีคำถามมากมายเกี่ยวกับสิ่งที่ไม่ได้รับการโหวตให้เป็นมาตรฐาน เรามีแท็ก C ++ 20 สำหรับเหตุผล ประเภทของสิ่งนี้เป็นอย่างมากในหัวข้อ
Nicol Bolas

1
@ cubuspl42 bar< foo::operator<=>เป็นตัวอย่างของความเป็นไปได้ของ<--โอเปอเรเตอร์
Yakk - Adam Nevraumont

8
@haccks: ใช่ Like C ++ 11 เป็นแท็กเกี่ยวกับคอมไพเลอร์ที่ใช้ C ++ 11 และ C ++ 14 เป็นแท็กเกี่ยวกับคอมไพเลอร์ที่ใช้ C ++ 14 และ C ++ 17 เป็นคอมไพเลอร์ที่ใช้ C ++ 17 ไม่ C ++ 20 เป็นแท็กสำหรับเนื้อหาเกี่ยวกับ C ++ 20 และเนื่องจากคำถามนี้เกี่ยวกับ C ++ 20 จึงมี แท็กวิกิที่ผิดไม่ใช่ตัวแท็กเอง
Nicol Bolas

คำตอบ:


180

สิ่งนี้เรียกว่าตัวดำเนินการเปรียบเทียบสามทาง

ตามข้อเสนอP0515 :

มีตัวดำเนินการเปรียบเทียบสามทาง<=>ใหม่ นิพจน์a <=> bส่งคืนวัตถุที่เปรียบเทียบ<0ถ้าa < bเปรียบเทียบ>0ถ้าa > bและเปรียบเทียบ==0ถ้าaและbเท่ากับ / เทียบเท่า

หากต้องการเขียนการเปรียบเทียบทั้งหมดสำหรับประเภทของคุณเพียงเขียนoperator<=>ที่ส่งคืนประเภทหมวดหมู่ที่เหมาะสม:

  • กลับ_orderingถ้าชนิดของคุณตามธรรมชาติสนับสนุน<และเราได้อย่างมีประสิทธิภาพจะสร้าง<, >, <=, >=, ==และ!=; มิฉะนั้นกลับ_equalityและเราได้อย่างมีประสิทธิภาพจะสร้าง ==และ! =

  • ผลตอบแทนที่แข็งแกร่งหากสำหรับประเภทของคุณa == bหมายถึงf(a) == f(b)(ทดแทนได้ที่ f อ่านเฉพาะรัฐเปรียบเทียบที่สำคัญสามารถเข้าถึงได้โดยใช้อินเทอร์เฟซ const แบบ nonprivate) มิฉะนั้นกลับอ่อนแอ

cppreferenceพูดว่า:

นิพจน์ตัวดำเนินการเปรียบเทียบสามทางมีฟอร์ม

lhs <=> rhs   (1)  

นิพจน์ส่งคืนวัตถุที่

  • เปรียบเทียบ<0ถ้าlhs < rhs
  • เปรียบเทียบ>0ถ้าlhs > rhs
  • และเปรียบเทียบ==0ว่าlhsและrhsเท่ากับ / เทียบเท่า

93
สำหรับผู้ที่สับสน (เช่นฉัน) เกี่ยวกับสิ่งที่ "เปรียบเทียบ<0", "เปรียบเทียบ>0" และ "เปรียบเทียบ==0" หมายถึงพวกเขาหมายถึง<=>ผลตอบแทนที่เป็นค่าลบบวกหรือศูนย์ขึ้นอยู่กับข้อโต้แย้ง เหมือนและstrncmp memcmp
Cornstalks

1
@ ไดแม้จะเป็นทั้งคู่'a' < 'a'และ'c' < 'a'เป็นเท็จทั้งคู่'a' < 'a'และ'a' < 'c'ไม่ใช่ ในการสั่งซื้อที่แข็งแกร่งดังต่อไปนี้เป็นจริง: a != ba < b || b < a
Revolver_Ocelot

1
@Rololver_Ocelot Ah ดังนั้นมันสามารถนิยาม / สร้างเป็นoperator==(T x, T y) { return !(x < y) && !(y < x); }และoperator!=(T x, T y) { return (x < y) || (y < x); }- ah-ha! แน่นอนว่ามันมีประสิทธิภาพน้อยกว่าของจริง==เพราะจะทำการเปรียบเทียบสองครั้ง แต่ก็ยังเรียบร้อย
Dai

3
"return strong" และ "return อ่อนแอ" หมายถึงอะไร?
lucidbrot

2
@ hkBattousai มันหมายความว่าวัตถุกลับมาเมื่อเปรียบเทียบกับการ< 0ประเมินจริง นั่นคือถ้าเป็นเช่นa < bนั้น(a <=> b) < 0จริงเสมอ
rmobis

116

เมื่อวันที่2017/11/11 , มาตรฐาน ISO c ++ คณะกรรมการนำมาใช้ สมุนไพร Sutterข้อเสนอ 's สำหรับ'ยานอวกาศ' ดำเนินการเปรียบเทียบสามทาง <=>เป็นหนึ่งในคุณสมบัติใหม่ที่ถูกเพิ่มเข้ามาในC ++ 20 ในบทความที่ชื่อว่าSutter Comparison ที่สอดคล้องกัน Maurer และ Brown แสดงให้เห็นถึงแนวคิดของการออกแบบใหม่ สำหรับภาพรวมของข้อเสนอนี่เป็นข้อความที่ตัดตอนมาจากบทความ:

นิพจน์a <=> bส่งคืนวัตถุที่เปรียบเทียบ<0ถ้า<bเปรียบเทียบ> 0ถ้าa> bและเปรียบเทียบ== 0ถ้า a และ b เท่ากับ / เทียบเท่า

กรณีทั่วไป:หากต้องการเขียนการเปรียบเทียบทั้งหมดสำหรับประเภทXของคุณด้วยประเภทYพร้อมซีแมนทิกส์ความหมายสมาชิกเพียงเขียน

auto X::operator<=>(const Y&) =default;

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

  • ส่งคืน_orderingหากประเภทของคุณรองรับ<และเราจะสร้างสมมาตร< , > , <= , > = , == , และ ! = ; มิฉะนั้นกลับ_equalityและเราได้อย่างมีประสิทธิภาพจะสร้างสมมาตร==และ! =
  • ย้อนกลับstrong_ถ้าสำหรับประเภทของคุณ== มาขหมายถึงf (ก) == f (ข) (ทดแทนที่อ่านเพียงรัฐเปรียบเทียบเด่นที่สามารถเข้าถึงได้โดยใช้ประชาชนconstสมาชิก) มิฉะนั้นกลับ weak_

หมวดเปรียบเทียบ

การเปรียบเทียบห้าหมวดหมู่ถูกกำหนดเป็นstd::ประเภทโดยแต่ละประเภทมีค่าที่กำหนดไว้ล่วงหน้าดังต่อไปนี้:

+--------------------------------------------------------------------+
|                  |          Numeric  values          | Non-numeric |
|     Category     +-----------------------------------+             |
|                  | -1   | 0          | +1            |   values    |
+------------------+------+------------+---------------+-------------+
| strong_ordering  | less | equal      | greater       |             |
| weak_ordering    | less | equivalent | greater       |             |
| partial_ordering | less | equivalent | greater       | unordered   |
| strong_equality  |      | equal      | nonequal      |             |
| weak_equality    |      | equivalent | nonequivalent |             |
+------------------+------+------------+---------------+-------------+

การแปลงโดยนัยระหว่างประเภทเหล่านี้มีการกำหนดไว้ดังนี้:

  • strong_orderingด้วยค่า { less, equal, greater} โดยปริยายแปลงไป:
    • weak_orderingด้วยค่า { less, equivalent, greater}
    • partial_orderingด้วยค่า { less, equivalent, greater}
    • strong_equalityด้วยค่า { unequal, equal, unequal}
    • weak_equalityด้วยค่า { nonequivalent, equivalent, nonequivalent}
  • weak_orderingด้วยค่า { less, equivalent, greater} โดยปริยายแปลงไป:
    • partial_orderingด้วยค่า { less, equivalent, greater}
    • weak_equalityด้วยค่า { nonequivalent, equivalent, nonequivalent}
  • partial_orderingด้วยค่า { less, equivalent, greater, unordered} โดยปริยายแปลงไป:
    • weak_equalityด้วยค่า { nonequivalent, equivalent, nonequivalent, nonequivalent}
  • strong_equalityด้วยค่า { equal, unequal} แปลงเป็น:
    • weak_equalityด้วยค่า { equivalent, nonequivalent}

การเปรียบเทียบสามทาง

<=>โทเค็นเป็นที่รู้จัก ลำดับอักขระโท<=>เค็<= >นในรหัสต้นฉบับเก่า ตัวอย่างเช่นX<&Y::operator<=>ต้องการเพิ่มช่องว่างเพื่อรักษาความหมายของมัน

ผู้ประกอบการ overloadable <=>เป็นฟังก์ชั่นการเปรียบเทียบสามทางและมีความสำคัญสูงกว่าและต่ำกว่า< <<ส่งคืนชนิดที่สามารถเปรียบเทียบกับตัวอักษร0แต่อนุญาตให้ส่งคืนชนิดอื่นเช่นสนับสนุนเทมเพลตนิพจน์ <=>ตัวดำเนินการทั้งหมดที่กำหนดไว้ในภาษาและในไลบรารีมาตรฐานส่งคืนหนึ่งในstd::ประเภทการเปรียบเทียบ5 ประเภทดังกล่าวข้างต้น

สำหรับประเภทภาษา<=>จะมีการเปรียบเทียบชนิดเดียวกันในตัวต่อไปนี้ ทั้งหมดเป็นconstexprยกเว้นที่ระบุไว้เป็นอย่างอื่น การเปรียบเทียบเหล่านี้ไม่สามารถเรียกคืนได้อย่างหลากหลายโดยใช้การส่งเสริม / แปลงสเกลาร์

  • สำหรับboolครบถ้วนและประเภทตัวชี้ผลตอบแทน <=>strong_ordering
  • สำหรับประเภทตัวชี้คุณสมบัติ cv ที่แตกต่างกันและการแปลงที่ได้รับมาจากฐานจะได้รับอนุญาตให้เรียกใช้บิวด์อินที่เป็นเนื้อเดียวกัน<=>และมีความหลากหลายในoperator<=>(T*, nullptr_t)ตัว การเปรียบเทียบพอยน์เตอร์กับวัตถุ / การจัดสรรเดียวกันเท่านั้นคือนิพจน์คงที่
  • สำหรับชนิดจุดลอยพื้นฐานให้<=>ส่งคืนpartial_orderingและสามารถเรียกใช้แบบ heterogeneously โดยขยายอาร์กิวเมนต์ให้เป็นประเภทจุดลอยขนาดใหญ่
  • สำหรับ enumerations, ผลตอบแทนเช่นเดียวกับการแจงนับเป็นพื้นฐานของประเภท<=><=>
  • สำหรับnullptr_t, <=>ผลตอบแทนและอัตราผลตอบแทนเสมอstrong_orderingequal
  • สำหรับอาร์เรย์T[N] <=> T[N]ที่คัดลอกได้จะส่งคืนชนิดเดียวกับTของ<=>และดำเนินการเปรียบเทียบองค์ประกอบตามพจนานุกรม ไม่มี<=>สำหรับอาร์เรย์อื่น ๆ
  • สำหรับการไม่มีvoid<=>

เพื่อทำความเข้าใจการทำงานภายในของผู้ประกอบการนี้โปรดอ่านต้นฉบับกระดาษ นี่คือสิ่งที่ฉันค้นพบโดยใช้เครื่องมือค้นหา


1
ราวกับว่า CPP ไม่ซับซ้อนพออยู่แล้ว ทำไมไม่เพียงแค่เขียนวิธีเปรียบเทียบ ...
Leandro

6
@Leandro ผู้ประกอบการยานอวกาศคือวิธีการเปรียบเทียบ นอกจากนี้มันใช้งานได้และเขียน (หรือลบ) ตัวดำเนินการเปรียบเทียบอีกหกรายการ ฉันจะใช้ฟังก์ชันโอเปอเรเตอร์การเปรียบเทียบหนึ่งรายการซึ่งเขียนทับแต่ละแผ่นข้อมูลต้นแบบหกชุด
ไม่ระบุชื่อ

โปรดทราบว่า_equalityประเภทนั้นเสียชีวิต: กลายเป็นว่า<=>เล่นได้ดีกับตัวดำเนินการสัมพันธ์สี่ตัว แต่ไม่ดีกับตัวดำเนินการที่เท่าเทียมกันสองตัว
Davis Herring

12

คำตอบนี้ไม่เกี่ยวข้องเนื่องจากหน้าเว็บที่อ้างอิงมีการเปลี่ยนแปลง

หน้าเว็บที่คุณกำลังอ้างอิงเสีย มันถูกแก้ไขมากในวันนั้นและส่วนต่าง ๆ ไม่ซิงค์กัน สถานะเมื่อฉันดูมันคือ:

ที่ด้านบนของหน้าจะแสดงรายการตัวดำเนินการเปรียบเทียบที่มีอยู่ในปัจจุบัน (ใน C ++ 14) ไม่มีที่<=>นั่น

ที่ด้านล่างของหน้าควรมีรายชื่อผู้ให้บริการรายเดิม แต่ทำผิดและเพิ่มข้อเสนอแนะในอนาคต

gccไม่ทราบเกี่ยว<=>ๆ (และ-std=c++14ไม่เคยจะ) a <= > bดังนั้นจึงคิดว่าคุณหมายถึง นี่คือคำอธิบายข้อผิดพลาด

หากคุณลองสิ่งเดียวกันห้าปีนับจากนี้คุณอาจได้รับข้อความแสดงข้อผิดพลาดที่ดีขึ้น <=> not part of C++14.


1
ลิงก์ OP ของหน้าเว็บนั้นถูกต้องเช่นเดียวกับหน้าที่แยกต่างหากที่คุณเชื่อมโยงไปถึง มันมีคุณสมบัติ<=>ผู้ประกอบการที่มีฉลาก (ตั้งแต่ C ++ 20) บอกคุณว่ามาตรฐานของรุ่นที่จะคาดหวังมันป้ายมาตรฐานเป็นแบบแผนที่ cppreference.com ดังต่อไปนี้ แน่นอนว่าคุณไม่มีคอมไพเลอร์ที่กลับมาในไทม์แมชชีนเพื่อสนับสนุนคุณ แต่ cpprefernce จะบอกคุณ (อย่างถูกต้อง) สิ่งที่คาดหวัง
Spencer

ใช่ แต่ ... ไม่ใช่คำตอบ คุณกำลังแสดงความคิดเห็น ... หรือบางสิ่งบางอย่าง
qlp

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