1. Changelog
-
R2 (post-Kona):
-
Removed five of the six proposed type-traits at LEWG’s request (see §6 Straw polls taken of LEWG in Kona (2019-02-18)). LEWG voted to forward this version to LWG for C++2a.
-
2. Strong structural equality should be static-assertable
The concept of "having strong structural equality" that was introduced by [P0732] will become important to programmers. Take this class type for example:
template < std :: size_t N > struct fixed_string { constexpr fixed_string ( const char ( & s )[ N + 1 ]) { std :: copy_n ( s , N + 1 , m_data ); } auto operator <=> ( const fixed_string & ) const = default ; char m_data [ N + 1 ]; };
This type’s
is a "structural comparison operator"
because it is defaulted, and invokes only other structural comparison operators. Since it yields
, it also has what we might call "strong structural ordering",
although this term is not introduced by P0732.
"Strong structural ordering" is a stricter requirement than P0732’s "strong structural equality,"
which is the prerequisite to use a user-defined type as a non-type template parameter.
C++ should permit the programmer to test the presence or absence of this property. Example:
static_assert ( std :: has_strong_structural_equality_v < fixed_string < 5 > > );
This permits maintainability-minded programmers to express their intention in code.
template < std :: size_t N > struct broken_fixed_string { constexpr broken_fixed_string ( const char ( & s )[ N + 1 ]) { std :: copy_n ( s , N + 1 , m_data ); } auto operator <=> ( const broken_fixed_string & rhs ) const { return std :: memcmp ( m_data , rhs . m_data , N + 1 ) <=> 0 ; } char m_data [ N + 1 ]; }; static_assert ( std :: has_strong_structural_equality_v < broken_fixed_string < 5 > > , "broken_fixed_string lacks the strong structural equality we expected" ); // ... possibly many lines of code here ... // ... possibly written by a different programmer ... template < auto V > struct A {}; A < broken_fixed_string ( "hello" ) > a ;
In the snippet above, we get a nice descriptive
failure, instead of an
unfriendly spew of diagnostics on the line that tries to instantiate
.
3. This feature benefits from compiler support
P1154R0 claimed that this type-trait could not be implemented without a compiler builtin.
In fact,
can be implemented according to standard C++17:
template < auto > struct A {}; template < class T , template < T > class = A > using B = void ; template < class T , class = void > struct HasStrongStructuralEquality : std :: false_type {}; template < class T > struct HasStrongStructuralEquality < T , B < T >> : std :: true_type {}; static_assert ( HasStrongStructuralEquality < int >:: value ); static_assert ( ! HasStrongStructuralEquality < std :: string >:: value );
This code relies on subtle and maybe-uncertain rules governing when
is a valid argument for a parameter of type
.
-
GCC currently does not support this code — that is, they fail the second
.static_assert -
MSVC flatly rejects it because they don’t support
template parameters yet.auto -
Clang accepts this code. The worst that can be said of Clang is that they give the wrong answer for
, but that can easily be worked around on the library side.HasStrongStructuralEquality < int &&>
Right now the burden is on the application programmer to know this trivia and come up with workarounds for GCC and MSVC. We propose to simplify the programmer’s job by putting this trait into the standard library, where the burden will be on the library to get it right (probably using a compiler builtin).
4. Provide just the one type trait
P1154R1 proposed six type-traits, with implementations shown in terms of a
hypothetical compiler builtin
. After the adoption
of [P1185], the general notion of "structural comparison" is no longer meaningful; the
new core-language feature is "strong structural equality" (only).
Strong structural equality may be provided by a structural (defaulted)
or by a structural (defaulted)
. In the latter case, the type might not
support
at all.
Therefore we propose only the following type-trait, with accompanying
variable template.
For exposition purposes only, we provide a sample implementation in terms of
a hypothetical compiler builtin
.
template < class T > struct has_strong_structural_equality : bool_constant < __has_strong_structural_equality ( T ) > {};
5. Proposed wording for C++2a
Add one new entry to Table 47 in [meta.unary.prop]:
Template Condition Preconditions
template < class T > struct has_strong_structural_equality ; The type has strong structural equality (10.10.1).
T T shall be a complete type, cv , or an array of unknown bound.
void
6. Straw polls taken of LEWG in Kona (2019-02-18)
SF | F | N | A | SA | |
---|---|---|---|---|---|
We want all of the traits [from P1154R1] (rather than just strong structural equality). | 0 | 2 | 4 | 0 | 3 |
Drop everything but , make sure to coordinate with [P1185], and forward to LWG for C++20.
| 3 | 5 | 1 | 0 | 0 |