There is no way to globally order all types at compile time; access to things like typeid(T).before(typeid(U))
is not constexpr
. So you cannot make two arbitrary meta_set<A,B>
and meta_set<B,A>
be the same type, as you cannot sort.
There is no way to modify the behavior of std::is_same
to return true if the types that are not the same. Any code that attempted to do so (say via specializing std::is_same
) would violate the requirements of std::is_same
, which would make the program ill-formed, no diagnostic required.
If you restricted your set of types to some subset of all types, you can do this. The easiest way would be to have a centralized list:
template<class...T>
struct types_t {};
using global_order = types_t<int, double, std::string>;
then, with some template metaprogramming, you can get the index of types in the global_order
, and then write a type-sorter based on this.
Then
template<class Types>
struct type_sorter;
template<class...Ts>
struct type_sorter<types_t<Ts...>> {
// todo
using type=types_t< result_somehow >;
};
Once that is written:
template<class...Ts>
using meta_set = typename type_sorter< types_t<Ts...> >::type;
would work.
There are probably solutions on how to sort stuff at compile time with templates on stack overflow. Personally I find merge sort easiest to write in template metaprogramming of all the n log(n) sorts. Last time it did it it took about 100-odd lines of dense template code? Including writing a TMP library. However, TMP libraries now exist, and may even have type-sorting code pre-written for you.
Now, a single global ordering is the easiest thing to do. We could make it a bit more powerful by teaching the type sorter about templates, ordering templates, and then ordering said template instances by their constituant types and values, etc.
That gets hard, and it requires work for each and every template, kind of template (so template<class...>class
vs template<class, std::size_t>class
) and base type (int
, float
, struct foo
) supported.
It would be a lot of work.
Slightly easier would be to write a custom trait
template<class Lhs, class Rhs>
struct smart_is_same;
that would act like std::is_same
, except when fed meta_set
s would check if they have the same contents instead of looking for strict type equality. However, your comments mention that this isn't your actual problem, but rather you are talking about passing the meta_set
arguments to a different template and wants them in a canonical order.