ãã®ããŒãžã¯C++20ã«æ¡çšãããèšèªæ©èœã®å€æŽã解説ããŠããŸãã
ã®ã¡ã®C++èŠæ Œã§ããã«å€æŽãããå Žåãããããé¢é£é ç®ãåç §ããŠãã ããã
æŠèŠ
æ°ããäžæ¹æ¯èŒæŒç®å<=>ãå°å
¥ãããããšã«ãããé åºä»ããšå倿¯èŒã®6ã€ã®é¢ä¿æŒç®åïŒ<, <=, >, >=, ==, !=ïŒã容æã«å®è£
ããããšãã§ããããã«ãªãã
#include <compare> //<=>å©çšã®å Žåå¿
é
#include <iostream>
struct C {
int x;
int y;
double v;
char str[32];
//<=>ãpublicã§å®çŸ©ããŠããããšã§ããã®ä»ã®æŒç®åãå°åºããã
auto operator<=>(const C&) const = default;
};
int main() {
C c1 = {10, 20, 3.1415, "Three-way Comparison" };
C c2 = {10, 20, 3.1415, "Spaceship Operator" };
//äžæ¹æ¯èŒæŒç®åãã®ãã®ã«ããæ¯èŒ
std::cout << ((c1 <=> c2) == 0) << std::endl;
std::cout << ((c1 <=> c2) < 0) << std::endl;
std::cout << ((c1 <=> c2) > 0) << std::endl;
//ã¯ã©ã¹Cã¯6ã€ã®æŒç®åã«ããæ¯èŒãå¯èœ
std::cout << (c1 < c2) << std::endl;
std::cout << (c1 <= c2) << std::endl;
std::cout << (c1 > c2) << std::endl;
std::cout << (c1 >= c2) << std::endl;
std::cout << (c1 == c2) << std::endl;
std::cout << (c1 != c2) << std::endl;
}
ãã®æ§ã«ãããã¯ã©ã¹ã«å¯ŸããŠäžæ¹æ¯èŒæŒç®å<=>ãå®çŸ©ããŠããããšã§æå€§6ã€ã®æ¯èŒæŒç®åãå°åºã䜿çšããããšãã§ããã
ãããŠããã®ãããª<=>ã¯defaultå®è£
ã§ååãªãã°å®è£
ãçç¥ã§ããã
ãã®æ§ãªäžæ¹æ¯èŒã®äºãäžè²«æ¯èŒïŒConsistent comparisonïŒãšèšãããã®æŒç®åã¯äžæ¹æ¯èŒæŒç®åïŒThree-way comparison operatorïŒãšåŒã¶ããŸããæŒç®åã®èŠãç®ããå®å®è¹æŒç®åïŒSpaceship operatorïŒãšåŒã°ããããšãããã
ãã®æ§ã«ãäžæ¹æ¯èŒæŒç®åãçšããã°æ¯èŒæŒç®åã®å®çŸ©ãéåžžã«å®¹æã«ãªãããstd::rel_opsã¯ãã®åœ¹å²ãã»ãšãã©å€±ããéæšå¥šãšãªã£ãã
仿§
äžæ¹æ¯èŒ
ããåã®å€a, bã«ã€ããŠã®a <=> bã«ããæ¯èŒã®çµæã¯åçŽãªboolã§ã¯ãªããæªæºã»çããã»è¶
ããããšãã3ã€ã®é¢ä¿ãåæã«è¡šãå€ãè¿ãã
ããããa, bã®é¢ä¿ãboolã®åœ¢ã§åŸãã«ã¯ã0ãªãã©ã«ãšã®æ¯èŒãçšããã
int a = 10;
int b = 20;
auto comp = a <=> b;
if (comp < 0) {
std::cout << "a < b";
} else if (0 < comp) {
std::cout << "a > b";
} else if (comp == 0) {
std::cout << "a = b";
}
ãã®å Žåã®çµæã¯a < bãåºåãããã
æ»ãå€ã®å€ã¯å·ŠèŸºã«å¯Ÿããå³èŸºã®é¢ä¿ã衚ãã®ã§ãåŒæ°é ãå
¥ãæ¿ãããšé åºã®æ¹åãé転ããïŒäžèšã®äŸã®å Žåãcomp = b <=> aãšãããšcomp < 0 == false, 0 < comp == trueãšãªããa > bãåºåãããïŒãããã¯ãæ°å€åã®å Žåã¯å·ŠèŸº-å³èŸºã®çµæã0ãã倧ãããïŒã«ãã£ãŠæ¯èŒçµæã衚çŸããŠãããšèŠãããšãã§ããã
ãªããäžæ¹æ¯èŒæŒç®åã®æ»ãå€ã®0ãªãã©ã«ä»¥å€ãšã®æ¯èŒã¯æªå®çŸ©åäœãšãããã1ã ã£ãã0.0ã§ãã£ãŠã¯ãªããªãã
int a = 10;
int b = 20;
auto comp = a <=> b;
//å
šãŠæªå®çŸ©åäœ
bool is_less = comp == 1;
bool is_greater = -1 < comp;
bool is_equal = comp == 0.0;
æ¯èŒã«ããŽãªåïŒComparison category typeïŒ
äžæ¹æ¯èŒæŒç®åã®æ»ãå€åã¯intãªã©ã®æŽæ°åã§ã¯ãªããæ¯èŒã«ããŽãªåãšåŒã°ããå°çšã®åã§ããã
ããã¯ãæ¯èŒå¯Ÿè±¡ãšãªãåã®æºãããŠããåå€ãé åºã®é¢ä¿ã«ã€ããŠãå°çšã®åã«ãã£ãŠè¡šæããã³ã³ã»ããçã®æ©æ§ã«ãã£ãŠãã®æ§è³ªã«å¿ããé©åãªåŠçãžã®ãã£ã¹ããããè¡ãããšãåºæ¥ãããã«ããããã§ããïŒäŸãã°ãåŸã§èª¬æãã<=>æŒç®åã®åæã®éã«å©çšãããŠãããïŒã
以äžã®3ã€ã®æ¯èŒã«ããŽãªåãæäŸãããã
| æ¯èŒã«ããŽãªå | 察å¿ããæ°åŠçãªé¢ä¿ | å°åºãããæŒç®å |
|---|---|---|
partial_ordering |
åé åº | == != < <= > >= |
weak_ordering |
匱é åº | == != < <= > >= |
strong_ordering |
å šé åº | == != < <= > >= |
衚ã«ããããã«3ã€ã®æ¯èŒã«ããŽãªåã¯ããããæ°åŠçãª2é é¢ä¿ïŒé åºé¢ä¿ïŒã®äžã€ãšå¯Ÿå¿ããŠããã
äžæ¹æ¯èŒæŒç®åã«ããæ¯èŒã®çµæãšãªãå€ã¯ããããæ¯èŒã«ããŽãªåã®ããããã®prvalueãªããžã§ã¯ããšãªãã
å
šãŠã®ã«ããŽãªã«ãããŠãã®ãããªãªããžã§ã¯ãã®0ãªãã©ã«ä»¥å€ãšã®æ¯èŒã¯æªå®çŸ©åäœãåŒãèµ·ããã
ãããã®æ¯èŒã«ããŽãªåã¯æ°ãã远å ããã<compare>ãããã«ãŠå®çŸ©ããããã<=>ãã³ãŒãäžã§äœ¿çšãããšããŠãèªåã§ã€ã³ã¯ã«ãŒããããªãããã<=>ã®äœ¿çšãå«ããŠæ¯èŒã«ããŽãªåãå©çšããéã¯<compare>ãæç€ºçã«ã€ã³ã¯ã«ãŒãããå¿
èŠãããã
æ¯èŒã«ããŽãªéã®é åºé¢ä¿
忝èŒã«ããŽãªåã¯ãã®æ¡ä»¶ã®åŒ·ããã®ãã匱ããã®ãžã®æé»å€æãå®çŸ©ãããããã®æ¹åã¯åã«ããŽãªã«å¯Ÿå¿ããæ°åŠçãªé¢ä¿ã®å å«é¢ä¿ã«ãã£ãŠå®çŸ©ãããŠããã

å³1 æ¯èŒã«ããŽãªéã®å€æé¢ä¿ïŒP0515R3ããåŒçšïŒ æçµçãªC++20仿§ã§ã¯weak_equality/strong_equalityã¯åé€ãããŠããïŒ
ã¯ã©ã¹åã«å¯Ÿããdefaultãªäžæ¹æ¯èŒæŒç®åã®æ§ã«è€æ°ã®åãåå ããäžæ¹æ¯èŒã®çµæã®æ¯èŒã«ããŽãªã¯ãæ¯èŒã«åå ãããã¹ãŠã®åã®<=>ã«ããæ¯èŒã®çµæãšãªãã«ããŽãªåããå
±éããŠå€æã§ããæã匷ãåãšãªãããã®ãããªåãå
±éæ¯èŒã«ããŽãªåïŒcommon comparison category typeïŒãšåŒã¶ã
æ¯èŒã«åå ãããã¹ãŠã®åã®<=>ã«ããæ¯èŒã«ããŽãªåãããããTi (0 <= i < N)ãšããŠãå
±éæ¯èŒã«ããŽãªåUã¯ä»¥äžã®ããã«æ±ºå®ãããã
Tiã®äžã«1ã€ã§ãpartial_orderingãããå ŽåãU = partial_ordering- ããã§ã¯ãªãã
Tiã®äžã«1ã€ã§ãweak_orderingãããå ŽåãU = weak_ordering - ãã以å€ã®å Žåã
U = strong_orderingïŒN == 0ã®å Žåãªã©ïŒ
ãã®å
±éæ¯èŒã«ããŽãªåãæ±ããã®ã¯å Žåã«ãã£ãŠã¯å°é£ãªã®ã§ããããæ±ããããã«<compare>ãããã«ãŠcommon_comparison_category<Ts...>ãšããã¡ã¿é¢æ°ãæäŸãããã
operator==
<=>ãå©çšããäºã§æå€§6ã€ã®æ¯èŒæŒç®åãå°åºããããšèª¬æããããå®éã«ã¯å倿¯èŒæŒç®åïŒ== !=ïŒã¯<=>ããå°åºãããã==ã¯å®çŸ©ãããŠããå¿
èŠããã!=ã¯==ããå°åºãããã
ãã ãã<=>ãdefault宣èšããå Žåã¯åãã¢ã¯ã»ã¹æå®ã§==ãæé»çã«default宣èšããå©çšå¯èœã«ãªãããŸããæç€ºçã«defaultã§å®£èšããããšãã§ããã
ãã®ãããªdefaultã®==ã®æ»ãå€åã¯boolã§ããã!=ã®å°åºã«äœ¿çšããã==ãæ»ãå€åã¯boolã§ãªããã°ãªããªãã
ãã®ãããç°çš®å鿝èŒãç¹æ®ãªæ¯èŒãå®è£
ããããã«<=>ãç¬èªã«å®çŸ©ããå Žåã6Ã2åã®æ¯èŒæŒç®åå
šãŠãå°åºããããã«ã¯==ãç¬èªã«å®çŸ©ããªããã°ãªããªãã
//<=>ãç¬èªå®è£
ã==ãå®è£
ããŠããªãåãïŒçš®é¡ã®æ¯èŒæŒç®åã«ããæ¯èŒãå¯èœ
struct not_eq_comparable {
char str[5];
auto operator<=>(const not_eq_comparable& that) const -> std::weak_ordering {
//倧æåå°æåãåå€ãšããŠæ±ã£ãŠæ¯èŒ
for (std::size_t i = 0; i < sizeof(this->str); ++i) {
char l1 = std::tolower(this->str[i]);
char l2 = std::tolower(that.str[i]);
if (l1 != l2) {
return l1 <=> l2;
}
}
return std::weak_ordering::equivalent;
}
};
{
not_eq_comparable str1 = {"test"}, str2 = {"TEST"};
//<=>ãdefaultã§ã¯ç¡ãã®ã§==ã¯å®çŸ©ãããŠããªã
bool eq1 = str1 == str2; //error
bool eq2 = (str1 <=> str2) == 0; //ok
bool ne1 = str1 != str2; //error
bool ne2 = (str1 <=> str2) != 0; //ok
}
//<=>ãš==äž¡æ¹å®è£
ãããåã6çš®é¡å
šãŠã®æ¯èŒæŒç®åã䜿çšå¯èœ
struct eq_comparable {
char str[5];
auto operator<=>(const eq_comparable& that) const -> std::weak_ordering {
//倧æåå°æåãåå€ãšããŠæ±ã£ãŠæ¯èŒ
for (std::size_t i = 0; i < sizeof(this->str); ++i) {
char l1 = std::tolower(this->str[i]);
char l2 = std::tolower(that.str[i]);
if (l1 != l2) {
return l1 <=> l2;
}
}
return std::weak_ordering::equivalent;
}
bool operator==(const eq_comparable& that) const {
//倧æåå°æåãåå€ãšããŠæ±ã£ãŠæ¯èŒ
for (std::size_t i = 0; i < sizeof(this->str); ++i) {
if (std::tolower(this->str[i]) != std::tolower(that.str[i])) return false;
}
return true;
}
};
{
eq_comparable str1 = {"test"}, str2 = {"TEST"};
//==ãå®çŸ©ããŠããã®ã§å倿¯èŒæŒç®åã䜿çšå¯èœ
bool eq1 = str1 == str2; //ok
bool eq2 = (str1 <=> str2) == 0; //ok
bool ne1 = str1 != str2; //ok
bool ne2 = (str1 <=> str2) != 0; //ok
}
ãŸããdefaultãª<=>ã宣èšããããã§ç°çš®å鿝èŒã®ããã«==ãå®çŸ©ããŠããŸããšãæé»ã«å®£èšãããŠããdefaultã®==ã¯å®£èšãããªããªã£ãŠããŸãã®ã§æ³šæãå¿
èŠã§ããã
enum class category {
A,
B,
C
};
struct enum_wrap {
category cat{};
auto operator<=>(const enum_wrap&) const = default;
//ãã®å®£èšãå¿
èŠ
//bool operator==(const enum_wrap&) const = default;
auto operator<=>(const category other_cat) const noexcept {
return cat <=> other_cat;
}
bool operator==(const category other_cat) const noexcept {
return cat == other_cat;
}
};
enum_wrap a = {category::A};
enum_wrap b = {category::B};
auto comp1 = a <=> b; //ok
auto comp2 = a <=> category::C; //ok
bool eq1 = a == b; //ng
bool eq2 = a == category::C; //ok
ãã®å Žåã§ããdefaultã®==ãæç€ºçã«å®£èšããããšã§å©çšå¯èœãšãªãã
ãã®ãããªä»æ§ã«ãªã£ãŠããã®ã¯ã<=>ãçšããå倿¯èŒã«ãããŠçºçããããªãŒããŒããããåé¿ããããã§ããïŒè©³çްã¯åŸè¿°ã®ãæ€èšãããã»ãã®éžæè¢ããåç
§ïŒã
æŒç®åã®å°åºãšãªãŒããŒããŒãåè£
<=>åã³==ããå°åºãããæŒç®åã¯æé»çã«å®£èšããå®è£
ãããŠããããã§ã¯ãªãããããã®æŒç®åãåŒã³åºããéã®ãªãŒããŒããŒãåè£ã«ã<=> ==ãå©çšããŠçæããåè£ãå
¥ããããšã«ãã£ãŠå°åºãããããã®ãããå°åºãããæ¯èŒæŒç®åã®ã¢ãã¬ã¹ãåãããšã¯åºæ¥ãªãã
è©³çŽ°ãªæé ã¯ä»¥äžã®ããã«ãªãã
ä»»æã®æŒç®å@ãä»»æã®åT1, T2ã®ãªããžã§ã¯ãa, bã«å¯ŸããŠa @ bã®ããã«åŒã³åºãããšã
- ãªãŒããŒããŒãåè£ã«ã
a @ bãå ãã @ãäžæ¹æ¯èŒæŒç®åãªãã°ããã®ãªãŒããŒããŒãåè£ã«<=>ã䜿ã£ãŠçæããéé ã®åŒb <=> aãå ãã@ãé¢ä¿æŒç®åïŒ< <= > >=ïŒãªãã°ããã®ãªãŒããŒããŒãåè£ã«<=>ã䜿ã£ãŠçæãã2çš®é¡ã®åŒa <=> b, b <=> aãå ãã@ã!=ãªãã°ããã®ãªãŒããŒããŒãåè£ã«==ã䜿ã£ãŠçæãã2çš®é¡ã®åŒa == b, b == aãå ãã@ã==ãªãã°ããã®ãªãŒããŒããŒãåè£ã«==ã䜿ã£ãŠçæããéé ã®åŒb == aãå ãã- ãªãŒããŒããŒã解決ã§ã¯äœ¿çšå¯èœãªã¡ã³ãã»éã¡ã³ãã»çµã¿èŸŒã¿ã®
@ <=> ==ãèæ ®ããã@âæ£é ã®åŒâéé ã®åŒ ã®é ã§åªå ãããããŸããéžæãããæŒç®åã«å¯ŸããŠåŒã®çæã¯è¡ãããªãã - ãããã®åè£ããã®ãªãŒããŒããŒã解決ã®çµæçæãããåè£ãéžæãããå Žåããã®åè£ã«å¿ããŠä»¥äžã®ããã«æçµçãªåŒãçæãã
@ãäžæ¹æ¯èŒæŒç®åãªãã°ã0 <=> (b <=> a)@ãé¢ä¿æŒç®åïŒ< <= > >=ïŒãªãã°ã(a <=> b) @ 0ãããã¯0 @ (b <=> a)@ã!=ãªãã°ã!(a == b)ãããã¯!(b == a)
- å
ã®åŒã³åºã
a @ bãçæãããåŒã§æžãæããïŒçæãããåŒãå ã®åŒã³åºãa @ bãšããŠå®è¡ããïŒ
çµæãåæŒç®åãåŒã³åºãããšãã«èæ ®ããããªãŒããŒããŒãåè£ã¯ä»¥äžã®ããã«ãªãã
åŒã³åºãæŒç®å a @ b |
ãªãŒããŒããŒãåè£ |
|---|---|
a <=> b |
a <=> b 0 <=> (b <=> a) |
a == b |
a == b(b == a) |
a != b |
a != b!(a == b)!(b == a) |
a < b |
a < b(a <=> b) < 00 < (b <=> a) |
a <= b |
a <= b(a <=> b) <= 00 <= (b <=> a) |
a > b |
a > b(a <=> b) > 00 > (b <=> a) |
a >= b |
a >= b(a <=> b) >= 00 >= (b <=> a) |
ãã®æ§ã«ãç°çš®å鿝èŒã«ãããŠãçæ¹ã®<=> ==ãå®çŸ©ããŠããã°ãã®åŒæ°é ãéã«ããæŒç®åãçæãããæŒç®åã®å¯Ÿç§°æ§ãèªåã§è£å®ãããã
ãã ãããã®æäœ¿çšããã==ã¯æ»ãå€åãboolïŒCV修食ã¯å¯ïŒã§ãªããã°ãªããã<=>ã¯çµæãšããŠ@ 0ãããã¯0 @ãé©çšå¯èœãªåãè¿ããªããã°ãªããªããããã§ãªãå Žåã¯ã³ã³ãã€ã«ãšã©ãŒãšãªãïŒäžèšæé 7以éã«çºçãããšã©ãŒã¯ã³ã³ãã€ã«ãšã©ãŒãšãªãïŒã
== <=>ã䜿çšå¯èœã§ã¯ãªãïŒå®çŸ©ãããŠãªããææ§ãã¢ã¯ã»ã¹ã§ããªããåé€ãããŠããïŒå Žåã¯ããªãŒããŒããŒã解決ã®éçšã§åè£ããå€ããã³ã³ãã€ã«ãšã©ãŒãšã¯ãªããªãïŒäžèšæé 6以åã®ãšã©ãŒã¯ã³ã³ãã€ã«ãšã©ãŒãšãªããªãïŒã
defaultæ¯èŒ
ãããŸã§ã«ã説æããã«ç»å ŽããŠããããããã¯ã©ã¹åã«å¯Ÿãã<=>ããã³==æŒç®åã¯defaultæå®ããããšãã§ããã
ããããå Žåãã³ã³ãã€ã©ã«ãã£ãŠãã®ã¯ã©ã¹ã®åºåºåã³å
šã¡ã³ãã®å®£èšé ã®èŸæžåŒæ¯èŒãè¡ãå®è£
ãæé»ã«å®çŸ©ãããã
ããã¯ã©ã¹Cã«å¯Ÿãã<=> ==ã®defaultæå®ã§ãã宣èšã¯ãCã®é¢æ°ãã³ãã¬ãŒãã§ãªãã¡ã³ããšããŠå®£èšãããŠããŠããã€const C&åã®1ã€ã®åŒæ°ããã€ééçconstã¡ã³ã颿°ïŒvolatileããã³åç
§ä¿®é£Ÿã¯èš±å¯ãããªãïŒã§ããããconst C&åãCåã®2ã€ã®åŒæ°ãæã€Cã®friend颿°ãã§ããå¿
èŠãããã
ã€ãŸã以äžã®æ§ãªå®£èšãæå¹ã§ããã
struct C {
//æå¹ãª<=>ã®default宣èšäŸ
auto operator<=>(const C&) const = default;
friend auto operator<=>(const C&, const C&) = default;
friend auto operator<=>(C, C) = default;
//æå¹ãª==ã®default宣èšäŸ
bool operator==(const C&) const = default;
friend bool operator==(const C&, const C&) = default;
friend bool operator==(C, C) = default;
//ã¯ã©ã¹å€ã§å®çŸ©ããããšãã§ãã
auto operator<=>(const C&) const;
bool operator== (const C&) const;
friend auto operator<=>(const C&, const C&);
friend bool operator== (const C&, const C&);
};
//ã¯ã©ã¹å€å®çŸ©ã¯å¥ã®ç¿»èš³åäœã«ãã£ãŠãok
auto C::operator<=>(const C&) const = default;
bool C::operator== (const C&) const = default;
inline auto operator<=>(const C&, const C&) = default;
inline bool operator== (const C&, const C&) = default;
ãã®ãããªdefault宣èšã¯ãã®å®çŸ©ãconstexpr颿°ã®èŠä»¶ãæºãããŠããã°æé»çã«constexpræå®ãããåŒã³åºãæŒç®åãå
šãŠnoexceptã§ãããªãã°æé»çã«noexceptã§ããããããã®æå®ïŒããã³virtual, constevalïŒã¯æç€ºçã«æå®ããŠããããšãã§ããããæç€ºçã«constexpr(consteval)æå®ããå Žåã¯æ¬äœãconstexpr颿°ã®èŠä»¶ãæºãããŠããªããã°ã³ã³ãã€ã«ãšã©ãŒãšãªãããŸããããã¯ã©ã¹ã«å¯Ÿããæåã®default宣èšãã¯ã©ã¹å
éšã§è¡ãããŠããå Žåã¯æé»çã«inlineæå®ãããã
defaultæå®ãããäžæ¹æ¯èŒæŒç®åã®æ»ãå€åã¯åºåºã¯ã©ã¹åã³å
šã¡ã³ãã®<=>ã®çµæåã®å
±éæ¯èŒã«ããŽãªåãšãªããããã®äžã«æ¯èŒã«ããŽãªåãè¿ããªã<=>ã«ããæ¯èŒãããå Žåã¯æé»çã«deleteãããã
deleteãããŠããªãå
šãŠã®defaultæ¯èŒæŒç®åã¯ãéåžžã®ç¹æ®ã¡ã³ã颿°ãšåæ§ã«ODR䜿çšãããæãããã¯å®æ°åŒã§è©äŸ¡ãããæã«ãæåã®default宣èšã®äœçœ®ã§æé»çã«å®çŸ©ãããïŒè©³çްã¯ãè©äŸ¡ãããªãæèã§ã®å®æ°åŒè©äŸ¡ã«ãã£ãŠç¹æ®ã¡ã³ã颿°ãã€ã³ã¹ã¿ã³ã¹åãããããšãèŠå®ããåç
§ïŒã
operator==ã®æé»å®£èš
äžèšã®ããã«<=>ãdefault宣èšãããŠããŠoperator==ã¡ã³ã/friend颿°ãäžã€ã宣èšãããŠããªãå Žåããã®<=>ã«å¯Ÿå¿ãã==ã®default宣èšãæé»çã«è¡ãããã
ãã®ãããªæé»å®£èšã¯å¯Ÿå¿ãã<=>ã®çŽåŸã§ããã®<=>宣èšã®æ»ãå€åãboolãååãoperator==ã«çœ®ãæããããã«å®£èšããããããªãã¡ã察å¿ãã<=>ã«æå®ãããŠããããããããããã£ãå
šãŠç¶æ¿ããããã ããçµæçãªäŸå€æå®ã ãã¯ç°ãªãå¯èœæ§ãããã
<=>ã®default宣èšã«äŒŽãæé»ã®==宣èšã®äŸã
template<typename T>
struct X {
friend constexpr std::partial_ordering operator<=>(X, X) requires (sizeof(T) != 1) = default;
//察å¿ãã==ã®æé»å®£èšã¯æ¬¡ã®ããã«ãªã
//friend constexpr bool operator==(X, X) requires (sizeof(T) != 1) = default;
[[nodiscard]] virtual std::strong_ordering operator<=>(const X&) const = default;
//察å¿ãã==ã®æé»å®£èšã¯æ¬¡ã®ããã«ãªã
//[[nodiscard]] virtual bool operator==(const X&) const = default;
};
ãã®ãããª==ã®æé»å®£èšã¯ã察å¿ãã<=>ãæé»çã«deleteãããŠããå Žåã§ã宣èšãããã
defaultå®è£
default宣èšããã<=> ==æŒç®åã¯ãã®åºåºã¯ã©ã¹ãšééçã¡ã³ãã宣èšé ã«æ¯èŒããŠããããšã§å®è£
ãããã
ãã®æé ã¯ä»¥äžã®ããã«ãªãïŒæŒç®å@ã¯<=> ==ã®ã©ã¡ããïŒã
- åºåºã¯ã©ã¹ã®
@ãåŒã³åºããŠæ¯èŒãè¡ãããã®é çªã¯ç¶æ¿é ïŒ:ã®åŸãã«æžããŠããåãå·Šããå³ïŒãæ·±ãåªå ã§æ¯èŒãããã - 宣èšãããé çªïŒäžããäžïŒã§ééçã¡ã³ãã
@ã«ãã£ãŠæ¯èŒããã- ãã®æãé åã¯èŠçŽ ããšã«æ¯èŒããã
- ãããã®æ¯èŒã®éãçµæã
0ïŒ==ãªãtrueïŒãšãªããªãæç¹ã§ãã®çµæãè¿ããŠçµäºããã - åºåºã¯ã©ã¹ãã¡ã³ããç¡ãå Žåã
strong_ordering::equalïŒ==ãªãtrueïŒãè¿ããŠçµäºããã
ãã®æé ãæç€ºçã«æžããšä»¥äžã®æ§ãªå®è£ ã«ãªãã
class D : Base1, Base2 {
int x;
int y;
char str[3];
double v;
public:
//auto operator<=>(const D&) const = default;
auto operator<=>(const D& that) const {
if (auto comp = static_cast<const Base1&>(*this) <=> static_cast<const Base1&>(that); comp !=0) return comp;
if (auto comp = static_cast<const Base2&>(*this) <=> static_cast<const Base2&>(that); comp !=0) return comp;
if (auto comp = x <=> that.x; comp !=0) return comp;
if (auto comp = y <=> that.y; comp !=0) return comp;
if (auto comp = str[0] <=> that.str[0]; comp !=0) return comp;
if (auto comp = str[1] <=> that.str[1]; comp !=0) return comp;
if (auto comp = str[2] <=> that.str[2]; comp !=0) return comp;
return v <=> that.v;
}
//auto operator==(const D&) const = default;
auto operator==(const D& that) const {
if (bool comp = static_cast<const Base1&>(*this) == static_cast<const Base1&>(that); comp != true) return false;
if (bool comp = static_cast<const Base2&>(*this) == static_cast<const Base2&>(that); comp != true) return false;
if (bool comp = x == that.x; comp != true) return false;
if (bool comp = y == that.y; comp != true) return false;
if (bool comp = str[0] == that.str[0]; comp != true) return false;
if (bool comp = str[1] == that.str[1]; comp != true) return false;
if (bool comp = str[2] == that.str[2]; comp != true) return false;
return v == that.v;
}
};
ãã ããæ¬¡ã®ããããã«è©²åœããå Žåã«ã¯<=> ==ã®default宣èšã¯æé»çã«deleteããã
<=>ã¯deleteããã- 䜿çšå¯èœãª
<=>æŒç®åãèŠã€ãããªããã¢ããã <=>ã«ããæ¯èŒãæ¯èŒã«ããŽãªåãè¿ããªããã¢ããã
- 䜿çšå¯èœãª
==ã¯deleteããã- 䜿çšå¯èœãª
==æŒç®åãèŠã€ãããªããã¢ããã ==ã«ããæ¯èŒãboolã«å€æå¯èœãªåãè¿ããªããã¢ããã
- 䜿çšå¯èœãª
- äž¡æ¹ãšã
deleteããã- åç §åã¡ã³ããæã€
- 1ã€ä»¥äžã®ã¡ã³ã倿°ãæã€å¿åå ±çšäœãã¡ã³ãã«å«ã
- ãã®åã1ã€ä»¥äžã®ã¡ã³ã倿°ãæã€å ±çšäœã§ãã
defaultå®è£ ã«ããã<=>ã®åæ
<=>ã®defaultæ¯èŒå®è£
ã¯ã¡ã³ãããã³åºåºã¯ã©ã¹ã«<=>ãæããªãåããããšæé»deleteããããããããããã§ã¯çŸåšäœ¿ãããŠããå€ãã®<=>ãæããªãåãã¡ã³ãã«æã€éã«defaultã®<=>ãæäŸã§ããªãã
ããããã®å Žåã«ãã<=>ã®default宣èšã«æ»ãå€åãæå®ããäžã§<=>ãæããªãã¡ã³ãïŒåºåºïŒåã< ==ã®2ã€ã®æŒç®åãå®è£
ããŠããã°ãããããå
ã«ããŠ<=>ãåæããäžã§defaultå®è£
ãè¡ãããšãã§ããã
//C++17以åã«äœæããã<=>ãæããªãå
struct legacy {
int n = 10;
//å
±ã«å®è£
ã¯çç¥
bool operator==(const legacy&) const;
bool operator< (const legacy&) const;
};
//C++20ç°å¢ã§äœæãããåã<=>ãå®è£
ããã
struct newer {
int m = 10;
legacy l = {20}; //<=>ãæã£ãŠããªã
int n = 30;
//ãã宣èšãããšæé»delete
//auto operator<=>(const newer&) const = default;
//legacyã®æ¯èŒã«é¢ããŠã¯æå®ããæ»ãå€åãšlegacyã®æã€æ¯èŒæŒç®å< ==ãçšããŠå®è£
ã䜿çšå¯èœ
std::strong_ordering operator<=>(const newer&) const = default;
};
newer n1{}, n2 = {20, {30}, 40};
auto comp = n1 <=> n2; //ok
bool eq = n1 == n2; //ok
<=>ã®default宣èšã«æå®ãããæ»ãå€åãRãæ¯èŒããããšããŠãã察å¿ããã¡ã³ãã®å€ãa, bãšããŠããããã®æºããæ¡ä»¶ã«ãã£ãŠä»¥äžã®ããã«<=>ã¯åæãããã
| æ¡ä»¶ | åæããã<=>ã®åŒ |
|---|---|
a <=> bã䜿çšå¯èœ |
static_cast<R>(a <=> b); |
Rã¯std::strong_orderingã§ãããa == b, a < bããããã䜿çšå¯èœ |
a == b ? std::strong_ordering::equal :a < b ? std::strong_ordering::less :std::strong_ordering::greater; |
Rã¯std::weak_orderingã§ãããa == b, a < bããããã䜿çšå¯èœ |
a == b ? std::weak_ordering::equivalent :a < b ? std::weak_ordering::less :std::weak_ordering::greater; |
Rã¯std::partial_orderingã§ãããa == b, a < bããããã䜿çšå¯èœ |
a == b ? std::partial_ordering::equivalent :a < b ? std::partial_ordering::less :b < a ? std::partial_ordering::greater;std::partial_ordering::unordered |
| ã©ãã«ãåœãŠã¯ãŸããªã | å®çŸ©ãããªã |
ãã®åæãããåŒãçšããŠ<=>ã®defaultå®è£
ãè¡ãæãåæãããåŒãå®çŸ©ãããªãïŒäžèšæ¡ä»¶ã«åœãŠã¯ãŸããªãïŒãã¢ãããå Žåã¯ãã®<=>ã®default宣èšã¯æé»çã«deleteãããã
å
ã»ã©ã®newerã«å¯ŸããŠæç€ºçã«æžããšä»¥äžã®ããã«ãªãã
struct newer {
int m = 10;
legacy l = {20}; //<=>ãæã£ãŠããªã
int n = 30;
//std::strong_ordering operator<=>(const newer&) const = default;
std::strong_ordering operator<=>(const newer& that) const {
if (auto comp = static_cast<std::strong_ordering>(m <=> that.m); comp != 0) return comp;
//legacyåã«å¯Ÿãã<=>ã®åæ
std::strong_ordering comp = (l == that.l) ? std::strong_ordering::equal :
(l < that.l) ? std::strong_ordering::less
: std::strong_ordering::greater;
if (comp != 0) return comp;
return static_cast<std::strong_ordering>(n <=> that.n);
}
};
ãã®åæã«ãããŠäœ¿çšããã< ==æŒç®åã®æ»ãå€åã®åŠ¥åœæ§ã¯ãã§ãã¯ãããªããä»®ã«boolã§ã¯ãªãã£ããšããŠããåæãããåŒã«ãããŠã³ã³ãã€ã«ãšã©ãŒãçºçããªããã°<=>ã®åæã¯ã€ã€ããªãè¡ããããéã«èšããšãåæãããåŒãã³ã³ãã€ã«ãšã©ãŒãèµ·ããå Žåã¯ããŒããšã©ãŒãšãªãã
ãã®ä»ã®æ¯èŒæŒç®åã®default宣èš
<=> ==ã ãã§ãªããæ®ãã®æ¯èŒæŒç®åãdefaultæå®ã§å®£èšããããšãã§ããããã®æå¹ãªå®£èšã¯==ã«åŸãã
ãã®ãããªdefaultå®è£
ã¯ãªãŒããŒããŒã解決æã«çæãããåŒãšåæ§ã®åŒã䜿ã£ãŠ<=> ==ããå®è£
ãããã
ãã ãæ¬¡ã®ããããã®å ŽåãæŒç®å@ïŒ< <= > >= !=ã®ããããïŒã®default宣èšã¯æé»çã«deleteãããïŒãªãŒããŒããŒãåè£çææã¯ã³ã³ãã€ã«ãšã©ãŒãšãªãå Žåã§ãåã«deleteãããïŒã
x @ yã®ãªãŒããŒããŒã解決ã®çµæã䜿çšå¯èœãªåè£ãèŠã€ãããªãx @ yã®ãªãŒããŒããŒã解決ã®çµæãçæãããåŒã§ã¯ãªãæŒç®åãèŠã€ãã£ãoperator@ããã§ã«å®çŸ©ãããŠãã
struct C {
// æ»ãå€åã®ãããã<=>
bool operator<=>(const C&) const { return true; }
// æ£åžžãª==
bool operator==(const C&) const = default;
bool operator<(const C&) const = default; //okãæé»çã«deleteããã
bool operator!=(const C&) const = default; //okã䜿çšå¯èœïŒãã ãã==ãæç€ºçã«å®£èšãããŠããå¿
èŠãããïŒ
};
ããã¯ãæ¯èŒæŒç®åã®ã¢ãã¬ã¹ãåããããšãã«äœ¿çšããã
çµã¿èŸŒã¿åã®äžæ¹æ¯èŒ
äžæ¹æ¯èŒæŒç®åã¯voidãstd::nullptr_tã颿°/ã¡ã³ããã€ã³ã¿ãããã³åç
§åãé€ãçµã¿èŸŒã¿ã®åã«å¯ŸããŠãçµã¿èŸŒã¿ã®ç©ãæäŸãããã
ãã®æ¯èŒã«ããŽãªåã¯ä»¥äžã®ããã«ãªãïŒä»¥äžãæ¯èŒãšã¯<=>ã«ãããã®ãæãïŒã
| å | ã«ããŽãª | åè |
|---|---|---|
bool |
std::strong_ordering |
boolå士ã§ããæ¯èŒäžå¯ |
æŽæ°å |
std::strong_ordering |
çž®å°å€æãè¡ãããå Žåã¯æ¯èŒäžå¯ |
æµ®åå°æ°ç¹å |
std::partial_ordering |
çž®å°å€æãè¡ãããå Žåã¯æ¯èŒäžå¯NaNã±0.0ã®ååšã®ããåé åº |
| ãªããžã§ã¯ããã€ã³ã¿ | std::strong_ordering |
ãããããã€ã³ã¿å€æãæœãããåŸãåããã€ã³ã¿åã«ãªããªããã°æ¯èŒäžå¯ é åãšé åã¯æ¯èŒäžå¯ ã©ã¡ããã®åŒæ°ãæŽæ°åããã«ãã€ã³ã¿å®æ°ã§ããå Žåãæ¯èŒäžå¯ |
| åæå | std::strong_ordering |
ã¹ã³ãŒãæç¡ã«é¢ãããåãåæåå士ã§ããæ¯èŒäžå¯ |
ãªããåç
§åã«å¯Ÿãã<=>ã«ããæ¯èŒã¯åç
§å
ã®åã«ããæ¯èŒã«ãªãã
åŸæ¥ã®æ¯èŒæŒç®åãšã®å·®ç°åã³ä¿®æ£
äžæ¹æ¯èŒæŒç®å<=>ã«ããæ¯èŒã¯ãåŸæ¥ã®æ¯èŒæŒç®å(< > <= >= == !=)ã®æåãšã¯ç°ãªããšãããããïŒããå®å
šãªæ¯èŒãšãªã£ãŠããïŒã
ããã«äŒŽã£ãŠãããã€ãã®æ¯èŒæŒç®åã®æåãä¿®æ£ãããïŒC++20ã§ã¯éæšå¥šãšãããçŠæ¢ãããŠã¯ããªãïŒã
| æ¯èŒããã㢠| <=>ã§ã®æ¯èŒã®å¯åŠ |
C++17ãŸã§ã®åŸæ¥æŒç®åã§ã®æ¯èŒã®å¯åŠ | C++20ããã®éæšå¥šå |
|---|---|---|---|
| 笊å·ãªãæŽæ°åãšç¬Šå·ä»æŽæ°å | à ãã ã宿°åŒã§ç¬Šå·ä»ããªãã©ã³ããæ£ã®å€ã«è©äŸ¡ãããã°å¯èœ |
ã | â |
| åæåãšç®è¡å | â³ ã¹ã³ãŒãç¡ãåæåãšæŽæ°åã®ã¿å¯èœ |
ã äŸãã°ãåæåãšæµ®åå°æ°ç¹åã®æ¯èŒãå¯èœ |
åæåãšæµ®åå°æ°ç¹åã®æ¯èŒã®ã¿éæšå¥š |
| ç°ãªãåæåé | à | ã | éæšå¥š |
| é åå士 | à | â³ å é èŠçŽ ãžã®ãã€ã³ã¿ã®æ¯èŒã«ãªã |
éæšå¥š |
| ãã«ãã€ã³ã¿å®æ°ãšãã€ã³ã¿ | à | â³ å倿¯èŒã®ã¿å¯èœ |
â |
衚äžã®èšå·ã®æå³
- ã : æ¯èŒå¯èœ
- â³ : å¶éããããæ¯èŒå¯èœ
- à : æ¯èŒäžå¯èœ
- â : 倿Žãªã
C++17ãŸã§ã®æ¯èŒæŒç®åå®è£ ã®äžäŸ
#include <iostream>
#include <tuple>
struct S {
int x;
double d;
char str[4];
constexpr bool operator<(const S& rhs) const {
return std::tie(x, d, str[0], str[1], str[2], str[3])
< std::tie(rhs.x, rhs.d, rhs.str[0], rhs.str[1], rhs.str[2], rhs.str[3]);
}
constexpr bool operator==(const S& rhs) const {
return std::tie(x, d, str[0], str[1], str[2], str[3])
== std::tie(rhs.x, rhs.d, rhs.str[0], rhs.str[1], rhs.str[2], rhs.str[3]);
}
constexpr bool operator!=(const S& rhs) const {
return !(*this == rhs);
}
constexpr bool operator>(const S& rhs) const {
return rhs < *this;
}
constexpr bool operator<=(const S& rhs) const {
return !(*this > rhs);
}
constexpr bool operator>=(const S& rhs) const {
return !(*this < rhs);
}
};
int main()
{
S s1 = {10, 0.1, "abc"};
S s2 = {10, 0.1, "ABC"};
std::cout << std::boolalpha;
std::cout << (s1 < s2) << std::endl;
std::cout << (s1 <= s2) << std::endl;
std::cout << (s1 > s2) << std::endl;
std::cout << (s1 >= s2) << std::endl;
std::cout << (s1 == s2) << std::endl;
std::cout << (s1 != s2) << std::endl;
}
åºå
false
false
true
true
false
true
C++20ã§ã®æ¯èŒæŒç®åå®è£ äŸ
#include <compare>
#include <iostream>
struct S {
int x;
double d;
char str[4];
auto operator<=>(const S&) const = default;
};
int main()
{
S s1 = {10, 0.1, "abc"};
S s2 = {10, 0.1, "ABC"};
std::cout << std::boolalpha;
std::cout << (s1 < s2) << std::endl;
std::cout << (s1 <= s2) << std::endl;
std::cout << (s1 > s2) << std::endl;
std::cout << (s1 >= s2) << std::endl;
std::cout << (s1 == s2) << std::endl;
std::cout << (s1 != s2) << std::endl;
}
åºå
false
false
true
true
false
true
ãã®æ©èœãå¿ èŠã«ãªã£ãèæ¯ã»çµç·¯
C++17以åã®äŸã«ç€ºããããã«ãåŸæ¥ã®C++ã«ãããæ¯èŒæŒç®åã®å®è£
ã¯ç
©éã§ãã€ã©ãŒãã¬ãŒãã®æ§ãªã³ãŒãã倧éã«ã³ããŒã¢ã³ãããŒã¹ãããããšã«ãªããããã«ãç°çš®å鿝èŒãå ãããšãã®å¯Ÿç§°æ§ã®ããã«åãæ¯èŒã«ã€ããŠåŒæ°åãéã«ãããã®ãçšæããªããã°ãªããªãããããã®ãããªãã€ã©ãŒãã¬ãŒãã¯æŽã«åã«ãªãããšã«ãªãã
ãã®åé¡ã¯ä»¥åããèªèãããŠãããæ¯èŒæŒç®åãå®éã«ã¯< ==ã®2ã€ããæ®ãã®ãã¹ãŠãå°åºã§ããããšãå©çšããŠå®è£
ãç°¡æã«ãããBoost Operators Libraryãstd::rel_opsçãæäŸãããŠããããããããããçšããŠãç°çš®å鿝èŒã«ããããã€ã©ãŒãã¬ãŒããå®å
šã«åãé€ãããšã¯åºæ¥ãªãã
ãŸããæ¯èŒæŒç®åã®å®è£
ã«äŒŽãå¥ã®åé¡ãšããŠãã¯ã©ã¹ã®å
šã¡ã³ããåå ãããããªæ§é çãªæ¯èŒãæäŸããéã«ããã¡ã³ãã®åææ¹æ³ãç¡ãããã«å
šãŠã®ã¡ã³ãã<ã==ã§ç¹ãã§åãã³ãŒããæžãããšã匷ããããŠããã
æ¯èŒæŒç®åå®è£
ã®å€ãã®å Žåã¯ãã®ãããªæ§é çãªæ¯èŒãæäŸããã°ååã§ããããã®å Žåã¯ã¯ã©ã¹ã«ãã£ãŠã¡ã³ãåçãéãã©å
šã¡ã³ãã®èŸæžåŒæ¯èŒãè¡ããšããç¹ã«å€ããã¯ãªãã
ãããã®åé¡ã®è§£æ±ºãèšèªæ©èœã«ãã£ãŠæäŸããããã«ãäžæ¹æ¯èŒæŒç®åãå°å ¥ãããã
äžã§ç€ºããããã«ãä»»æã®ã¯ã©ã¹åã«å¯Ÿããæ¯èŒæŒç®åã®å®è£
ã¯<=>ã1ã€å®çŸ©ããã ãã§å®çµããããã®æ¯èŒãæ§é çãªãã®ã§ãããªãã°ãdefaultæå®ããããšã§å®çŸ©ãæžãå¿
èŠãããªãã
ãããŠãdefaultæå®ããã<=>ãš==ã¯åºåºã¯ã©ã¹åã³å
šã¡ã³ãã®å®£èšé ã®èŸæžåŒæ¯èŒãè¡ãã
ç°çš®å鿝èŒã«ãããŠãã1ã€ã®åŒæ°é ã®<=>ãš==ã®2ã€ãå®çŸ©ããããšã§æ®ãã®11åã®æ¯èŒæŒç®åãå°åºããããšãã§ããã
æ€èšãããã»ãã®éžæè¢
<=> != == : å倿¯èŒã®åé¢
åœåã®äžæ¹æ¯èŒæŒç®åããå°åºãããæŒç®åã¯å倿¯èŒïŒ== !=ïŒã®ãã®ãå«ããæå€§6ã€ã§ãã£ããããããå倿¯èŒãªãæ¯èŒã«ã€ããŠã®åŠçãç絡è©äŸ¡ã§ããå Žåã«ã<=>ãçšããŠ== !=ãå°åºãããšç絡è©äŸ¡ãè¡ãããéå¹çã«ãªãã±ãŒã¹ããã£ãããã<=>ãã==ãåãé¢ãã!=ã¯==ããå°åºããããã«å€æŽãããã
äŸãã°ãstd::vectorã§<=>ãå®è£
ããããšãèããŠã¿ãã
template<typename T>
strong_ordering operator<=>(const std::vector<T>& lhs, const std::vector<T>& rhs) {
size_t min_size = std::min(lhs.size(), rhs.size());
for (size_t i = 0; i != min_size; ++i) {
if (auto const cmp = std::compare_three_way(lhs[i], rhs[i]); cmp != 0) {
return cmp;
}
}
return lhs.size() <=> rhs.size();
}
ããã¯ãä¿æããèŠçŽ ã«å¯ŸããèŸæžåŒæ¯èŒãè¡ãå®è£
ã§æ¢åã®æ¯èŒæŒç®åãšç䟡ã®åŠçã§ããã
å®éã®æ¯èŒã¯compare_three_wayã«å§è²ããŠããããããã¯Tã«<=>ãããã°ãããå©çšãç¡ããã°<ãš==ã䜿ã£ãŠæ¯èŒãè¡ã颿°ã§ããïŒC++20ããå©çšå¯èœïŒã
ããã¯é åºä»ãã«ãããŠã¯åé¡ãªãããå倿¯èŒãè¡ãããšãããšéå¹çãªç¹ããããããã¯ãé·ãïŒãµã€ãºïŒãäžçªæåŸã«æ¯èŒããŠããããšã§ãå倿¯èŒã®å Žåã¯äžçªæåã«vectorã®é·ãããã§ãã¯ãç°ãªã£ãŠããã°ããã®æç¹ã§çµæãfalseã«ãªããšåããåŠçãçµããããšãã§ããã
åŸã£ãŠãvectorã«ããã==ã®å¹ççãªå®è£
ã¯ä»¥äžã®ããã«ãªãã
template<typename T>
bool operator==(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
//ãµã€ãºãå
ã«ãã§ãã¯ããããšã§æ¯èŒãã·ã§ãŒããµãŒããã
const size_t size = lhs.size();
if (size != rhs.size()) {
return false;
}
for (size_t i = 0; i != size; ++i) {
//ãã¹ãããæ¯èŒã«ãããŠã<=>ã§ã¯ãªã==ã䜿ãïŒããã«ãããïŒ
if (lhs[i] != rhs[i]) {
return false;
}
}
return true;
}
template<typename T>
bool operator!=(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
return !(lhs == rhs);
}
ãã®æ§ã«ããŠããã°ãvectorã®ãªããžã§ã¯ãå士ã®å倿¯èŒã«ãããŠã¯åžžã«å¹ççãªå®è£
ãéžæãããã
ãšããã§ãåœåã®ä»æ§ã§ã¯== !=ãäžæ¹æ¯èŒæŒç®åããå°åºãããŠããããã®éã«çæããåŒã¯ä»¥äžã®ããã«èŠå®ãããŠããã
åŒã³åºãæŒç®å a @ b |
ãªãŒããŒããŒãåè£ |
|---|---|
a == b |
a == b(a <=> b) == 00 == (b <=> a) |
a != b |
a != b(a <=> b) != 00 != (b <=> a) |
ãã®åæã®äžã§äžèšã®å¹ççãª==å®è£
ãããvectorãä¿æããå¥ã®åãèããŠã¿ããšå°ã£ãããšãèµ·ããã
struct has_vector {
std::vector<string> vec;
auto operator<=>(const has_vector&) const = default;
};
has_vector hv1{}, hv2{};
//以äžã®äºã€ã®æ¯èŒã¯åœåææ¡ã®äžã§ã¯
bool eq = hv1 == hv2;
bool ne = hv1 != hv2;
//ãã®ããã«å±éããã
bool eq = (hv1 <=> hv2) == 0;
bool ne = (hv1 <=> hv2) != 0;
ãã®has_vectorã¯ã©ã¹ã¯ä»¥åã®ä»æ§ã®äžã§ã<=>ãå©çšããŠ6ã€ã®æ¯èŒæŒç®åã«ããæ¯èŒãå¯èœã§ããã
ãããããã®has_vectorã¯ã©ã¹ã®ãªããžã§ã¯ãã«å¯ŸããŠ== !=ã«ããæ¯èŒãè¡ã£ãæãåŒã³åºãããã®ã¯vectorã«å®çŸ©ããã<=>ã§ãã£ãŠå¹ççã«å®è£
ããã==ã§ã¯ãªãã
ãã®has_vectorã®å倿¯èŒã«ãããŠãå
éšvectorã«å®è£
ãããå¹ççãª==ãåŒã³åºãã«ã¯ä»¥äžã®ããã«ããªããã°ãªããªãã
struct has_vector {
std::vector<string> vec;
auto operator<=>(const has_vector&) const = default;
bool operator==(const has_vector& that) const {
return vec == that.vec;
}
bool operator!=(const has_vector& that) const {
return vec != that.vec;
}
};
å
éšvectorã®== !=ãåŒã³åºãããã«has_vectorã«å¯Ÿãã== !=ãç¬èªã«å®çŸ©ããããããããã®has_vectorãã¡ã³ãã«æã€å¥ã®ã¯ã©ã¹ãããæãåæ§ã«ããªããã°ãªããªãã
ãŸãããã®æ§ãªæ°ããªãã€ã©ãŒãã¬ãŒãã®ã³ããŒã¢ã³ãããŒã¹ããå¿
èŠã«ãªããã©ããã¯ãã¯ã©ã¹ã®ã¡ã³ãåã®å
šãŠã®== !=æŒç®åã®å®è£
ãååž°çã«èŸ¿ã倿ããå¿
èŠãããã
ãã®ãããªæ°ããªç
©éãã®å°å
¥ã¯åœåã®äžè²«æ¯èŒãç®æããæ¹åæ§ãšã¯çéã§ãããRustãHaskellçã®ä»èšèªã«ãããŠãå倿¯èŒãšé åºä»ãã®æŒç®åã¯åºå¥ãããããã§èªåå®è£
ãè¡ãããŠããããšãããC++ã«ãããŠãåæ§ã«<=>ãã== !=ãåãé¢ãããããšãšãªã£ãã
ããããåœåã®äžè²«æ¯èŒä»æ§ã®ç°¡äŸ¿ããæãªããªãããã«ãdefaultå®è£
ã®<=>ãããã°æé»çã«==ã宣èšãããšãã仿§ã远å ããå¹ççãª==ã®å®è£
ãå¿
èŠãªãåã§ã¯åœåã®ä»æ§ã«ã»ãŒæ²¿ã£ãåœ¢ã§æ©æµãåããããšãã§ããã
åå€é¢ä¿ãè¡šãæ¯èŒã«ããŽãªã®åé€
åœåã®ä»æ§ã§ã¯ã<=>ã®æ¯èŒãåå€é¢ä¿ã®ã¿ãæºããããšã衚æãã2ã€ã®æ¯èŒã«ããŽãªåãå®çŸ©ãããŠããã
ãããã®åãè¿ã<=>ã«ããæ¯èŒã«ãããŠã¯ã== !=æŒç®åã®ã¿ãïŒ==æŒç®åã«ãã£ãŠïŒå°åºãããŠããã
| æ¯èŒã«ããŽãªå | 察å¿ããæ°åŠçãªé¢ä¿ | å°åºãããæŒç®å |
|---|---|---|
weak_equality |
åå€é¢ä¿ | == != |
strong_equality |
çžçé¢ä¿ïŒæã现ããåå€é¢ä¿ | == != |
ããããåé ã®å€æŽã«ãã£ãŠãããã®åã¯ã»ãšãã©ãã®åœ¹å²ã倱ãããŸããã®ã«ããŽãªä»ãã«ãåé¡ããã£ããããæ®ããŠããã®ã¯æ··ä¹±ããã°ã®ããšã§ãããšããŠåé€ãããã
ãŸããããã«äŒŽããããã®åãè¿ããŠããçµã¿èŸŒã¿ã®åã®æ¯èŒãåé€ãããã
| å | ã«ããŽãª | åè |
|---|---|---|
| 颿°/ã¡ã³ããã€ã³ã¿ | std::strong_equality |
ãããããã€ã³ã¿å€æãæœãããåŸãåããã€ã³ã¿åã«ãªããªããã°æ¯èŒäžå¯ |
std::nullptr_t |
std::strong_equality |
é¢é£é ç®
<compare>- æ¯èŒã«ããŽãªå
- ã³ã³ã»ãã
common_comparison_category- æ¯èŒé¢æ°ãªããžã§ã¯ã
<algorithm>- C++20 åæå€ããç®è¡åãžã®æé»å€æãéæšå¥šå
- C++20 çµã¿èŸŒã¿é åã®æ¯èŒãéæšå¥šå
åç §
- C++20ã«ãŠæ¿èªãããææ¡ææž
- P0515R3 Consistent comparison
- äžè²«æ¯èŒä»æ§ã®è¿œå
- P0768R1 Library support for the spaceship (comparison) operator
- æ¯èŒã«ããŽãªåã®æšæºã©ã€ãã©ãªãžã®å°å ¥
- P0905R1 Symmetry for spaceship
<=>ãã®ãã®ã®å¯Ÿç§°æ§è£å®
- P1120R0 Consistency improvements for <=> and other comparison operators
<=>ã«ããæ¯èŒãåºã«ããåŸæ¥ã®æ¯èŒæŒç®åã®ä¿®æ£
- P1185R2 <=> != ==
== !=ã®<=>ããã®åãé¢ã
- P1186R3 When do you actually use <=>?
- ã¡ã³ã倿°ã«
<=>ãæããªãåãããæãæ»ãå€åãš< ==ãçšããŠ<=>ãåæãã
- ã¡ã³ã倿°ã«
- P1630R1 Spaceship needs a tune-up
==ã®æ»ãå€åãbooléå®ã«ãããªã©ãäžè²«æ¯èŒä»æ§å šè¬ã®çްãããã°ä¿®æ£
- P1614R2 The Mothership has Landed (Adding <=> to the Library)
- æšæºã©ã€ãã©ãªã§æäŸãããã¯ã©ã¹ãžã®äžè²«æ¯èŒä»æ§ãããŒã¹ãšãã
<=> ==å°å ¥
- æšæºã©ã€ãã©ãªã§æäŸãããã¯ã©ã¹ãžã®äžè²«æ¯èŒä»æ§ãããŒã¹ãšãã
- P1959R0 Remove
std::weak_equalityandstd::strong_equality- äžèŠã«ãªã£ã
_equalityãªæ¯èŒã«ããŽãªåã®åé€
- äžèŠã«ãªã£ã
- P1946R0 Allow defaulting comparisons by value
<=> ==ã®friendãªdefault宣èšã®èª¿æŽ
- P2085R0 Consistent defaulted comparisons
<=> ==ã®default宣èšãã¯ã©ã¹å€ã§ãè¡ããããã«ãã
- P2002R1 Defaulted comparison specification cleanups
- ããã©ã«ãæ¯èŒã«ã€ããŠã®ä»æ§ã®ã¯ãªãŒã³ã¢ãããæé»
deleteããããšããæç¢ºã«ããã仿§ã®ç©ºçœãåãããªã©ã®èª¿æŽ
- ããã©ã«ãæ¯èŒã«ã€ããŠã®ä»æ§ã®ã¯ãªãŒã³ã¢ãããæé»
- P0515R3 Consistent comparison
- 以åã«æ€èšãããŠããææ¡ææž
- N3950 Defaulted comparison operators
- N4114 Defaulted comparison operators
- N4126 Explicitly defaulted comparison operators
- N4475 Default comparisons (R2)
- N4476 Thoughts about Comparisons (R2)
- P0221R2: Proposed wording for default comparisons, revision 4
- P0100R2 Comparison in C++
- P0436R1 An Extensible Approach to Obtaining Selected Operators
- P0474R0 Comparison in C++: Basic Facilities
- P0481R0 T. Van Eerd. âBravely Default
- P0432R0 D. Stone. âImplicit and Explicit Default Comparison Operators