Example
#include <typeinfo>
#include <type_traits>
static_assert(std::is_same_v<int, int>);
static_assert(typeid(int) == typeid(int));
static_assert(typeid(int) == typeid(const int));
static_assert(not std::is_same_v<int, const int>);
static_assert(typeid(int) == typeid(const int&));
static_assert(not std::is_same_v<int, const int&>);
Puzzle
- Can you implement
compare_types
function which compare given types by leveraging typeid comparison?
#include <typeinfo>
template<class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool; // TODO
static_assert(compare_types());
static_assert(compare_types<int>());
static_assert(compare_types<void>());
static_assert(compare_types<int, int>());
static_assert(compare_types<const int, int, int const>());
static_assert(compare_types<const int&, int>());
static_assert(compare_types<int&, int&&>());
static_assert(compare_types<int, int&&, int&, const int&, int const&&>());
static_assert(compare_types<int&, const int&>());
static_assert(compare_types<void, void, void>());
static_assert(not compare_types<int, float>());
static_assert(not compare_types<void*, const void*, void* const>());
static_assert(not compare_types<int, int*>());
static_assert(not compare_types<int*, int**>());
Solutions
template <class T, class U>
using types_equal_t = std::bool_constant<typeid(T) == typeid(U)>;
template<class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool {
using pairwise_equality_t = boost::mp11::mp_pairwise_fold<boost::mp11::mp_list<Ts...>, types_equal_t>;
return boost::mp11::mp_apply<boost::mp11::mp_all, pairwise_equality_t>::value;
}
consteval auto compare_types() -> bool{ return true; }
template<class T>
[[nodiscard]] consteval auto compare_types() -> bool{ return true; }
template<class R, class T, class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool{
return typeid(R) == typeid(T) && compare_types<T,Ts...>();
}
template<class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool
{
if constexpr (sizeof...(Ts) == 0) {
return true;
}
else {
auto helper = []<typename H, typename... Hs>() {
return ((typeid(H) == typeid(Hs)) && ...);
};
return helper.template operator()<Ts...>();
}
}
[nodiscard]] consteval auto compare_types() -> bool {
return true;
}
template <class T, class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool {
if constexpr (sizeof...(Ts) == 0) {
return true;
} else {
return (... and (typeid(T) == typeid(Ts)));
}
template<class... Ts>
[[nodiscard]] consteval bool compare_types();
template<class A, class B, class... Ts>
[[nodiscard]] consteval auto compare_2types_and_a_seq_of_types() -> bool {
return (typeid(A) == typeid(B)) && (compare_types<A, Ts...>());
}
template<class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool{
if constexpr(sizeof...(Ts) > 1){ return compare_2types_and_a_seq_of_types<Ts...>(); }
else { return true; }
}
template <class... Ts>
[[nodiscard]] constexpr auto compare_types() -> bool {
const std::type_info* type_ptrs[]{&typeid(std::remove_cvref_t<Ts>)...};
for (auto type_ptr : type_ptrs) {
if (*type_ptr != **type_ptrs) return false;
}
return true;
}
[[nodiscard]] consteval bool compare_types() {
return true;
}
template<class T1>
[[nodiscard]] consteval bool compare_types() {
return true;
}
template<class T1, class T2, class...Ts>
[[nodiscard]] consteval bool compare_types() {
return typeid(T1) == typeid(T2) and compare_types<T2, Ts...>();
}
template<typename ... Ts>
struct types{};
template<class... Ts>
consteval bool compare_types(){
constexpr auto n = sizeof...(Ts);
if constexpr (n == 0 || n == 1){ return true;
} else {
return []<typename U1, typename U2, typename ... Us>(types<U1, U2, Us ...>){
return typeid(U1) == typeid(U2) && compare_types<U2, Us ...>();
}(types<Ts...>{});
}
}
template<class... Ts>
[[nodiscard]] consteval auto compare_types() -> bool {
if constexpr( sizeof...(Ts) < 1)
return true;
else {
auto all_equal = []<typename T1, typename...Tr>() {
return ((typeid(T1) == typeid(Tr)) && ...);
};
return all_equal.template operator()<Ts...>();
}
}