1. Proposal
I propose to be three way comparable with an implementation-defined strong order, consistent with for reflections that represent types.
2. Background
[P2830R10] introduced , which exposes an implementation-defined strong order on types.
[P2996R13] (Reflecton for C++26) introduced as a structural type.
This means that class template specializations can have constant template arguments of type.
Therefore arbitrary reflection values are subject to ordering through indirection to class template specializations:
template < std :: meta :: info > struct S {}; // what comes first? int or the global namespace? constexpr bool b = std :: type_order < S <^^ int > , S <^^::>>:: value ;
3. Motivation
Being able to compare directly makes metaprogramming that needs to sort types, functions, etc... into some canonical order with standard algorithms more convenient.
Consider , one of the motivating examples of [P2830R10]:
With (status quo)
| With (proposed)
|
|---|---|
|
|
Moreover an ordering over reflections generalizes to cases where we want to order something other than types. For example getting a canonical order of annotations over a particular entity, instead of the lexical order.
4. Implementation
[P2830R10] argues that any should be consistent with .
I agree.
Implementing such a comparison between arbitrary values is possible, based on an existing implementation:
template < std :: meta :: info > struct _Helper {}; consteval std :: strong_ordering compare ( std :: meta :: info a , std :: meta :: info b ) { if ( is_type ( a ) && is_type ( b )) { // ensure that on types meta::info ordering is consistent with type_order auto ordering_info = static_data_members_of ( substitute ( ^^ std :: type_order , { a , b } ), std :: meta :: access_context :: unprivileged ())[ 0 ]; return extract < const std :: strong_ordering &> ( ordering_info ); } else if ( ! is_type ( a ) && ! is_type ( b )) { // indirect through helper class template for non-type reflections auto ordering_info = static_data_members_of ( substitute ( ^^ std :: type_order , { substitute ( ^^ _Helper , { std :: meta :: reflect_constant ( a )}), substitute ( ^^ _Helper , { std :: meta :: reflect_constant ( b )}), } ), std :: meta :: access_context :: unprivileged ())[ 0 ]; return extract < const std :: strong_ordering &> ( ordering_info ); } else { // non-types compare less than types return is_type ( a ) <=> is_type ( b ); } }
I have no implementation of the same comparison for built-in in a compiler.
5. Wording
Wording is relative to [N5032].
5.1. [basic.fundamental]
-
[Note 1:
,^^ int and^^ const int & compare unequal to each other. - end note]^^ int & -
[Note 2: This ordering need not be consistent with the one introduced by
, when applied to reflections that represent types. - end note]type_info :: before -
[Note 3: The ordering of reflections that represent TU-local entities from different translation units is not observable, because it is impossible to form corresponding relational or three-way comparison expressions. - end note]
5.2. [expr.spaceship]
std :: meta :: info , the result type is std :: strong_ordering . The result is std :: strong_ordering :: less if the first operand precedes the second operand, std :: strong_ordering :: equal if the operands compare equal, or std :: strong_ordering :: greater if the second operand precedes the first operand according to the implementation-defined strict total order of reflections ([basic.fundamental]).
5.3. [expr.rel]
std :: meta :: info
type.
std :: meta :: info , each of the operators shall yield true if the specified relationship is true corresponding to the implementation-defined strict total order of reflections ([basic.fundamental]), otherwise false.
5.4. [over.built]
std :: meta :: info
, there exist candidate operator functions of the form
bool operator==(T, T); bool operator!=(T, T); bool operator<(T, T); bool operator>(T, T); bool operator<=(T, T); bool operator>=(T, T); R operator<=>(T, T);
where R is the result type specified in [expr.spaceship].
std :: meta :: info ,std :: nullptr_t , there exist candidate operator functions of the form
bool operator==(T, T); bool operator!=(T, T);
5.5. [compare.type]
X and Y , the expression TYPE - ORDER ( X , Y ) is a constant expression ([expr.const]) of type strong_ordering ([cmp.strongord]).
Its value is strong_ordering :: less if X precedes Y in this implementation-defined total order, strong_ordering :: greater if Y precedes X , and strong_ordering :: equal if they are the same type.-
[Note 1 :,int andconst int are different types. — end note]int & -
[Note 2 : This ordering need not be consistent with the one induced by. — end note]type_info :: before -
[Note 3 : The ordering of TU-local types from different translation units is not observable, because the necessary specialization ofis impossible to name. — end note]type_order
template<class T, class U> struct type_order {
static constexpr strong_ordering value = TYPE-ORDER(T, U)^^T <=> ^^U;
using value_type = strong_ordering;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
5.6. [cpp.predefined]
#define __cpp_meta_info_order DATE-OF-ADOPTION