Implementing an `is_similar` type trait based on the definition of the C++ standard

Viewed 109

I am trying to implement a is_similar type trait based on the definition given by the standard (details here):

Two types T1 and T2 are similar if they have cv-decompositions with the same n such that corresponding Pi components are either the same or one is "array of Ni" and the other is "array of unknown bound of", and the types denoted by U are the same.

However, I am not sure to exactly understand what it means, and how to implement it:

template <class T, class U, class = void>
struct is_similar_base: std::false_type {};

template <class T, class U>
struct is_similar_base<T, U, /* ??? */ >: std::true_type {};

template <class T, class U>
struct is_similar: is_similar_base<T, U> {};

template <class T, class U>
inline constexpr bool is_similar_v = is_similar<T, U>::value;

Any help would be welcome.

1 Answers

cv-decomposition "peels" a type down into alternating layers of const/volatile qualifiers and pointer/array indirections. Types are similar if the pointer/array indirections are the same (allowing "array of unknown bound" to match "array of n") and if the types underneath are the same (ignoring the cv-qualifiers).

So,

// every type is similar to itself
template<typename T, typename U>
struct is_similar_impl : std::is_same<T, U> { };
// we don't care about cv-qualifiers
template<typename T, typename U>
struct is_similar : is_similar_impl<std::remove_cv_t<T>, std::remove_cv_t<U>> { };
// peeling off different kinds of pointers/arrays
template<typename T, typename U>
struct is_similar_impl<T*, U*> : is_similar<T, U> { };
template<typename C, typename T, typename U>
struct is_similar_impl<T C::*, U C::*> : is_similar<T, U> { };
template<std::size_t N, typename T, typename U>
struct is_similar_impl<T[N], U[N]> : is_similar<T, U> { };
template<std::size_t N, typename T, typename U>
struct is_similar_impl<T[N], U[]> : is_similar<T, U> { };
template<std::size_t N, typename T, typename U>
struct is_similar_impl<T[], U[N]> : is_similar<T, U> { };

template<typename T, typename U>
constexpr inline bool is_similar_v = is_similar<T, U>::value;

Godbolt and test cases

Related