{"id":5927,"date":"2020-06-16T13:46:07","date_gmt":"2020-06-16T13:46:07","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-20-more-details-to-the-spaceship-operator\/"},"modified":"2023-06-26T09:48:50","modified_gmt":"2023-06-26T09:48:50","slug":"c-20-more-details-to-the-spaceship-operator","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-20-more-details-to-the-spaceship-operator\/","title":{"rendered":"C++20: More Details to the Spaceship Operator"},"content":{"rendered":"<p>The compiler performs cleverly when it generates all six comparison operators. Ultimately, you get intuitive and efficient comparison operators for free. Let me dive into this post into the details of the spaceship operator.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5199\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/02\/TimelineCpp20.png\" alt=\"TimelineCpp20\" width=\"650\" height=\"250\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>First, I want to add something I should have written about in my first post to the three-way comparison operator: &#8220;<a href=\"https:\/\/bit.ly\/ThreeWayComparison\">C++20: The Three-Way Comparision Operator<\/a>&#8220;.<\/p>\n<h2>Direct Usage of the Three-Way Comparison Operator<\/h2>\n<p>You can directly use the spaceship operator:<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ spaceship.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;compare&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> a(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> b(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> res <span style=\"color: #555555;\">=<\/span> a <span style=\"color: #555555;\">&lt;=&gt;<\/span> b;                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"a &lt; b\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res <span style=\"color: #555555;\">==<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"a == b\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res <span style=\"color: #555555;\">&gt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"a &gt; b\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>string str1(<span style=\"color: #cc3300;\">\"2014\"<\/span>);\r\n    std<span style=\"color: #555555;\">::<\/span>string str2(<span style=\"color: #cc3300;\">\"2011\"<\/span>);\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> res2 <span style=\"color: #555555;\">=<\/span> str1 <span style=\"color: #555555;\">&lt;=&gt;<\/span> str2;          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res2 <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"str1 &lt; str2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res2 <span style=\"color: #555555;\">==<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"str1 == str2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res2 <span style=\"color: #555555;\">&gt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"str1 &gt; str2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> vec1{<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>};\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> vec2{<span style=\"color: #ff6600;\">1<\/span>, <span style=\"color: #ff6600;\">2<\/span>, <span style=\"color: #ff6600;\">3<\/span>};\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> res3 <span style=\"color: #555555;\">=<\/span> vec1 <span style=\"color: #555555;\">&lt;=&gt;<\/span> vec2;          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res3 <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"vec1 &lt; vec2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res3 <span style=\"color: #555555;\">==<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"vec1 == vec2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    <span style=\"color: #006699; font-weight: bold;\">else<\/span> <span style=\"color: #006699; font-weight: bold;\">if<\/span> (res3 <span style=\"color: #555555;\">&gt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"vec1 &gt; vec2\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>You can directly use the spaceship operator for <span style=\"font-family: courier new, courier;\">int<\/span>&#8216;s (1), <span style=\"font-family: courier new, courier;\">string<\/span>&#8216;s (2), and <span style=\"font-family: courier new, courier;\">vecto<\/span>r&#8217;s (3). Thanks to the<a href=\"https:\/\/wandbox.org\/\"> wandbox online-compiler <\/a>and the newest GCC, here is the program&#8217;s output.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5924\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/spaceship.png\" alt=\"spaceship\" width=\"250\" height=\"199\" style=\"display: block; margin-left: auto; margin-right: auto;\" \/><\/p>\n<p>Now, it&#8217;s time for something new in C++. C++20 introduces the concept of &#8220;rewritten&#8221; expressions.<\/p>\n<\/p>\n<h2>Rewriting Expressions<\/h2>\n<p>When the compiler sees something such as<span style=\"font-family: courier new, courier;\"> a &lt; b,<\/span> it rewrites it to <span style=\"font-family: courier new, courier;\">(a &lt;=&gt; b) &lt; 0 <\/span>using the spaceship operator<span style=\"font-family: courier new, courier;\">. <\/span><\/p>\n<p>Of course, the rule applies to all six comparison operators:<\/p>\n<p><strong><span style=\"font-family: courier new, courier;\">a OP<\/span> b<\/strong> becomes<strong><span style=\"font-family: courier new, courier;\"> (a &lt;=&gt; b) OP 0<\/span><\/strong>. It&#8217;s even better. If there is no conversion of the<span style=\"font-family: courier new, courier;\"> type(a)<\/span> to the<span style=\"font-family: courier new, courier;\"> type(b)<\/span>, the compiler generates the new expression<strong><span style=\"font-family: courier new, courier;\"> 0 OP (b &lt;=&gt; a)<\/span><\/strong>.<\/p>\n<p>For example, this means for the less-than operator, if <strong><span style=\"font-family: courier new, courier;\">(a &lt;=&gt; b) &lt; 0<\/span><\/strong> does not work, the compiler generates <strong><span style=\"font-family: courier new, courier;\">0 &lt; (b &lt;=&gt; a)<\/span><\/strong>. In essence, the compiler automatically takes care of the symmetry of the comparison operators. <span style=\"font-family: courier new, courier;\"><\/span><\/p>\n<p>Here are a few examples of the rewriting expressions:<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ rewrittenExpressions.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;compare&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">MyInt<\/span> {\r\n <span style=\"color: #9999ff;\">public:<\/span>\r\n    constexpr MyInt(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val)<span style=\"color: #555555;\">:<\/span> value{val} { }\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> MyInt<span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;  \r\n <span style=\"color: #006699; font-weight: bold;\">private<\/span><span style=\"color: #555555;\">:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> value;\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    constexpr MyInt myInt2011(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr MyInt myInt2014(<span style=\"color: #ff6600;\">2014<\/span>);\r\n   \r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> int2011(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> int2014(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (myInt2011 <span style=\"color: #555555;\">&lt;<\/span> myInt2014) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"myInt2011 &lt; myInt2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> ((myInt2011 <span style=\"color: #555555;\">&lt;=&gt;<\/span> myInt2014) <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"myInt2011 &lt; myInt2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; \r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (myInt2011 <span style=\"color: #555555;\">&lt;<\/span> int2014) std<span style=\"color: #555555;\">::<\/span> cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"myInt2011 &lt; int2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> ((myInt2011 <span style=\"color: #555555;\">&lt;=&gt;<\/span> int2014) <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">0<\/span>) std<span style=\"color: #555555;\">::<\/span> cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"myInt2011 &lt; int2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (int2011 <span style=\"color: #555555;\">&lt;<\/span> myInt2014) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"int2011 &lt; myInt2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> (<span style=\"color: #ff6600;\">0<\/span> <span style=\"color: #555555;\">&lt;<\/span> (myInt2014 <span style=\"color: #555555;\">&lt;=&gt;<\/span> int2011)) std<span style=\"color: #555555;\">::<\/span> cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"int2011 &lt; myInt2014\"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;     <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n}\r\n   \r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I used in (1), (2), and (3) the less-than operator and the corresponding spaceship expression. (4) is the most exciting example. It exemplifies how the comparison (<span style=\"font-family: courier new, courier;\">int2011 &lt; myInt2014<\/span>) triggers the generation of the spaceship expression (<span style=\"font-family: courier new, courier;\">0 &lt; (myInt2014 &lt;=&gt; int2011<\/span>).<\/p>\n<p><span style=\"font-family: courier new, courier;\">MyInt<\/span> has an issue.&nbsp; Constructors taking one argument should be explicit.<\/p>\n<h2>Explicit Constructor<\/h2>\n<p>Constructors taking one argument, such as <span style=\"font-family: courier new, courier;\">MyInt(int val)<\/span> are conversion constructors. In the concrete case, an instance from <span style=\"font-family: courier new, courier;\">MyInt<\/span> can be generated from any integral or floating-point value because each integral or floating-point value can implicitly be converted to <span style=\"font-family: courier new, courier;\">int<\/span>. I assume you don&#8217;t want implicit conversion from an integral or a floating-point value when an instance of <span style=\"font-family: courier new, courier;\">MyInt<\/span> is required.<span style=\"font-family: courier new, courier;\"><\/span><span style=\"font-family: courier new, courier;\"><\/span><\/p>\n<h3>First Try<\/h3>\n<p>To disable this implicit conversion, I make the constructor explicit following the Python meta-rule: explicit is better than implicit. The following program shows the explicit constructor:<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ threeWayComparisonWithInt1.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;compare&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">MyInt<\/span> {\r\n <span style=\"color: #9999ff;\">public:<\/span>\r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">explicit<\/span> MyInt(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val)<span style=\"color: #555555;\">:<\/span> value{val} { }\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> MyInt<span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;  \r\n <span style=\"color: #006699; font-weight: bold;\">private<\/span><span style=\"color: #555555;\">:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> value;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T, <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T2<span style=\"color: #555555;\">&gt;<\/span>\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">bool<\/span> isLessThan(<span style=\"color: #006699; font-weight: bold;\">const<\/span> T<span style=\"color: #555555;\">&amp;<\/span> lhs, <span style=\"color: #006699; font-weight: bold;\">const<\/span> T2<span style=\"color: #555555;\">&amp;<\/span> rhs) {\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> lhs <span style=\"color: #555555;\">&lt;<\/span> rhs;                                          <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>boolalpha <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    constexpr MyInt <span style=\"color: #cc00ff;\">myInt2011<\/span>(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr MyInt <span style=\"color: #cc00ff;\">myInt2014<\/span>(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    \r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">int2011<\/span>(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">int2014<\/span>(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(myInt2011, myInt2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(myInt2011, myInt2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n              \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(int2011, myInt2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(int2011, myInt2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n            \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(myInt2011, int2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(myInt2011, int2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n              \r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">auto<\/span> res <span style=\"color: #555555;\">=<\/span> isLessThan(myInt2011, int2014);\r\n              \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n              \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>This was easy. Thanks to the explicit constructor, the implicit conversion from int to<span style=\"font-family: courier new, courier;\"> MyInt i<\/span>n (1) is not valid anymore. The compiler now speaks an unambiguous message.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5925\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1.PNG\" alt=\"threeWayComparisonWithInt1\" width=\"700\" height=\"376\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1.PNG 3840w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1-300x161.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1-1024x549.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1-768x412.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1-1536x824.png 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt1-2048x1099.png 2048w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>When you read the error message carefully, you notice that there is no operator &lt; for a right-hand operand int available and no conversion from <span style=\"font-family: courier new, courier;\">int<\/span> to <span style=\"font-family: courier new, courier;\">MyIn<\/span>t possible. Interestingly, the compiler complains about (2) but not about (3). Both function calls cause a compiler error.<\/p>\n<h3>Second Try<\/h3>\n<p>To support the comparison from<span style=\"font-family: courier new, courier;\"> MyInt<\/span>&#8216;s and <span style=\"font-family: courier new, courier;\">int<\/span>&#8216;s, <span style=\"font-family: courier new, courier;\">MyInt<\/span> needs an additional three-way comparison operator.<\/p>\n<p>&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #009999;\">#include &lt;compare&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">MyInt<\/span> {\r\n <span style=\"color: #9999ff;\">public:<\/span>\r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">explicit<\/span> MyInt(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val)<span style=\"color: #555555;\">:<\/span> value{val} { }\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> MyInt<span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span> \r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> {  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> value <span style=\"color: #555555;\">&lt;=&gt;<\/span> rhs;\r\n    }\r\n <span style=\"color: #9999ff;\">private:<\/span> \r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> value;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T, <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T2<span style=\"color: #555555;\">&gt;<\/span>\r\nconstexpr <span style=\"color: #007788; font-weight: bold;\">bool<\/span> isLessThan(<span style=\"color: #006699; font-weight: bold;\">const<\/span> T<span style=\"color: #555555;\">&amp;<\/span> lhs, <span style=\"color: #006699; font-weight: bold;\">const<\/span> T2<span style=\"color: #555555;\">&amp;<\/span> rhs) {\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> lhs <span style=\"color: #555555;\">&lt;<\/span> rhs;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main() {\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>boolalpha <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    constexpr MyInt <span style=\"color: #cc00ff;\">myInt2011<\/span>(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr MyInt <span style=\"color: #cc00ff;\">myInt2014<\/span>(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    \r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">int2011<\/span>(<span style=\"color: #ff6600;\">2011<\/span>);\r\n    constexpr <span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">int2014<\/span>(<span style=\"color: #ff6600;\">2014<\/span>);\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(myInt2011, myInt2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(myInt2011, myInt2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl; <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span> \r\n              \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(int2011, myInt2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(int2011, myInt2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n            \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"isLessThan(myInt2011, int2014): \"<\/span>\r\n              <span style=\"color: #555555;\">&lt;&lt;<\/span> isLessThan(myInt2011, int2014) <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n              \r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">auto<\/span> res <span style=\"color: #555555;\">=<\/span> isLessThan(myInt2011, int2014);        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n              \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n              \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I defined in (1) the three-way comparison operator and declared it <span style=\"font-family: courier new, courier;\">constexpr<\/span>. The user-defined three-way comparison operator is in contrast to the compiler-generated three-way comparison operator, not <span style=\"font-family: 'courier new', courier;\">constexpr<\/span>. Consequently, I can perform the <span style=\"font-family: courier new, courier;\">isLessThan<\/span> (4) call at compile-time. Comparing <span style=\"font-family: courier new, courier;\">MyInt&#8217;<\/span>s and <span style=\"font-family: courier new, courier;\">int&#8217;<\/span>s is possible in each combination (3).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5926\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt2.PNG\" alt=\"threeWayComparisonWithInt2\" width=\"400\" height=\"171\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt2.PNG 1453w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt2-300x128.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt2-1024x438.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2020\/06\/threeWayComparisonWithInt2-768x329.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>I find the implementation of the various three-way comparison operators very elegant. The compiler auto-generates the comparison of <span style=\"font-family: courier new, courier;\">MyInt&#8217;<\/span>s, and the user defines the comparison with <span style=\"font-family: courier new, courier;\">int<\/span>&#8216;s explicitly.&nbsp; Additionally, you have to define only two operators to get 18 = 3 * 6 combinations of comparison operators. 3 represents the combination of <span style=\"font-family: courier new, courier;\">int<\/span>&#8216;s and<span style=\"font-family: courier new, courier;\"> MyInt<\/span>&#8216;s and 6 for the six comparison operators. I discussed in my last post, &#8220;<a href=\"https:\/\/bit.ly\/ThreeWayComparison\">C++20: The Three-Way Comparision Operator<\/a>&#8221;&nbsp; the 18 operators you had to overload before C++20.<\/p>\n<p>I want to make one point clear: You can even compare <span style=\"font-family: courier new, courier;\">MyInt<\/span> which each type that is convertible to <span style=\"font-family: courier new, courier;\">int<\/span>.<\/p>\n<p><strong>Stop!<\/strong> You may ask yourself: What is the current implementation using an explicit constructor<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #009999;\"><\/span><span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">MyInt<\/span> {\r\n <span style=\"color: #9999ff;\">public:<\/span>\r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">explicit<\/span> MyInt(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val)<span style=\"color: #555555;\">:<\/span> value{val} { }\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> MyInt<span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>; <span style=\"color: #0099ff; font-style: italic;\"><\/span>\r\n    constexpr <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> {  <span style=\"color: #0099ff; font-style: italic;\"><\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> value <span style=\"color: #555555;\">&lt;=&gt;<\/span> rhs;\r\n    }\r\n <span style=\"color: #9999ff;\">private:<\/span> \r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> value;\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>better than the previous implementation using a constructor capable of implicit conversions? Both classes allow comparisons with integrals and floating-point values.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\"><\/span><span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">MyInt<\/span> {\r\n <span style=\"color: #9999ff;\">public:<\/span>\r\n    constexpr MyInt(<span style=\"color: #007788; font-weight: bold;\">int<\/span> val)<span style=\"color: #555555;\">:<\/span> value{val} { }\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">&lt;=&gt;<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> MyInt<span style=\"color: #555555;\">&amp;<\/span> rhs) <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">default<\/span>;  \r\n <span style=\"color: #006699; font-weight: bold;\">private<\/span><span style=\"color: #555555;\">:<\/span>\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> value;\r\n};W\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>There is a subtle difference between an explicit and a non-explicit constructor for <span style=\"font-family: courier new, courier;\">MyInt<\/span> that you can easily see when I make <span style=\"font-family: courier new, courier;\">MyInt<\/span> more <span style=\"font-family: courier new, courier;\">int<\/span>-like in my <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-20-fast-comparison-with-the-spaceship-operator\">next post.<\/a> <span style=\"font-family: courier new, courier;\"><\/span>Additionally, the compiler-generated <span style=\"font-family: courier new, courier;\">==<\/span> and <span style=\"font-family: courier new, courier;\">!=<\/span> operators are special for performance reasons, and the interplay of classical comparison operators and the three-way comparison operator are worth an extra post.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The compiler performs cleverly when it generates all six comparison operators. Ultimately, you get intuitive and efficient comparison operators for free. Let me dive into this post into the details of the spaceship operator.<\/p>\n","protected":false},"author":21,"featured_media":5199,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[462],"class_list":["post-5927","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-spaceship"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5927","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5927"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5927\/revisions"}],"predecessor-version":[{"id":6737,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5927\/revisions\/6737"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5199"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5927"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5927"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5927"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}