Background
We know that the concept std::same_as
is agnostic to order (in other words, symmetric): std::same_as<T, U>
is equivalent to std::same_as<U, T>
(related question). In this question, I would like to implement something more general: template <typename ... Types> concept same_are = ...
that checks whether types in the pack Types
are equal to each other.
My attempt
#include <type_traits>
#include <iostream>
#include <concepts>
template <typename T, typename... Others>
concept same_with_others = (... && std::same_as<T, Others>);
template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);
template< class T, class U> requires are_same<T, U>
void foo(T a, U b) {
std::cout << "Not integral" << std::endl;
}
// Note the order <U, T> is intentional
template< class T, class U> requires (are_same<U, T> && std::integral<T>)
void foo(T a, U b) {
std::cout << "Integral" << std::endl;
}
int main() {
foo(1, 2);
return 0;
}
(My intention here is to enumerate over every possible ordered pair of types in the pack)
Unfortunately, this code would not compile, with the compiler complaining that the call to foo(int, int)
is ambiguous. I believe that it considers are_same<U, T>
and are_same<T, U>
as not equivalent. I would like to know why the code fails how I can fix it (so that the compiler treats them as equivalent)?