-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Describe the bug
As implemented in MS STL, ordering types in are default constructible and constructible from integer types.
test case
#include <compare>
#include <type_traits>
static_assert(std::is_default_constructible_v<std::strong_ordering>);
static_assert(std::is_constructible_v<std::strong_ordering, int>);
auto s1 = std::strong_ordering();
auto s2 = std::strong_ordering(42);;
https://godbolt.org/z/37oEMvxj8
Expected behavior
As specified in the standard, these constructions are not required to work, or required to not work, depending on the reading of [member.functions]/2 and the resolution of the recent [LWG4306].
Regardless of the resolution, allowing these constructions is undesirable, at least because the behavior diverges from other implementations which enables users to accidentally write non-portable code.
STL version
From the above godbolt link: x64 msvc v19.43 VS17.13
Possible resolution
Making the defaulted default constructor of the ordering types private could resolve this without requiring an ABI break, like so:
class ordering {
private:
ordering() = default;
public:
signed char value;
};
These ordering types are passed around in registers for parameters and for return. MSVC seems to require the type to satisfy C++14's definition of aggregate to pass it in register when returning it from a function. Making the default constructor explicitly defaulted and private still satisfies this definition, and the ordering type could still be returned in a register.
In turn it makes the type non-aggregate from C++20 onward (which is when the types are introduced to begin with), so it's not default constructible, not constructible from {}, and not constructible from integer types.
Additional context
isocpp-lib reflector thread: https://lists.isocpp.org/lib/2025/07/32342.php