I ran into this while debugging this question.
I trimmed it down all the way to just using Boost Operators:
-
#include <boost/operators.hpp> struct F : boost::totally_ordered1<F, boost::totally_ordered2<F, int>> { /*implicit*/ F(int t_) : t(t_) {} bool operator==(F const& o) const { return t == o.t; } bool operator< (F const& o) const { return t < o.t; } private: int t; }; int main() { #pragma GCC diagnostic ignored "-Wunused" F { 42 } == F{ 42 }; // OKAY 42 == F{42}; // C++17 OK, C++20 infinite recursion F { 42 } == 42; // C++17 OK, C++20 infinite recursion }
This program compiles and runs fine with C++17 (ubsan/asan enabled) in both GCC and Clang.
When you change the implicit constructor to
explicit
, the problematic lines obviously no longer compile on C++17
Surprisingly both versions compile on C++20 (v1 and v2), but they lead to infinite recursion (crash or tight loop, depending on optimization level) on the two lines that wouldn't compile on C++17.
Obviously this kind of silent bug creeping in by upgrading to C++20 is worrisome.
Questions:
- Is this c++20 behaviour conformant (I expect so)
- What exactly is interfering? I suspect it might be due to c++20's new "spaceship operator" support, but don't understand how it changes the behaviour of this code.