#include <type_traits>
#include <utility>
template <class T>
struct type_identity {
using type = T;
};
struct empty_class {};
template <class... Args>
struct builtin_common_type;
template <class... Args>
using builtin_common_type_t = typename builtin_common_type<Args...>::type;
template <class... Args>
struct builtin_common_type : __builtin_common_type<builtin_common_type_t, type_identity, empty_class, Args...> {};
template <class Tp, class Up>
using cond_result_t = decltype(false ? std::declval<Tp>() : std::declval<Up>());
template <class Tp, class Up, class = void>
struct common_type3 {};
template <class Tp, class Up>
struct common_type3<Tp, Up, std::void_t<cond_result_t<const Tp&, const Up&>>> {
using type = std::remove_cvref_t<cond_result_t<const Tp&, const Up&>>;
};
template <class Tp, class Up, class = void>
struct common_type2_imp : common_type3<Tp, Up> {};
// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
template <class Tp, class Up>
struct common_type2_imp<Tp, Up, std::void_t<decltype(true ? std::declval<Tp>() : std::declval<Up>())> > {
using type = std::decay_t<decltype(true ? std::declval<Tp>() : std::declval<Up>())>;
};
template <class, class = void>
struct common_type_impl {};
template <class... Tp>
struct common_types_tag;
template <class... Tp>
struct common_type;
template <class Tp, class Up>
struct common_type_impl<common_types_tag<Tp, Up>, std::void_t<typename common_type<Tp, Up>::type> > {
typedef typename common_type<Tp, Up>::type type;
};
template <class Tp, class Up, class _Vp, class... Rest>
struct common_type_impl<common_types_tag<Tp, Up, _Vp, Rest...>, std::void_t<typename common_type<Tp, Up>::type>>
: common_type_impl<common_types_tag<typename common_type<Tp, Up>::type, _Vp, Rest...> > {};
// bullet 1 - sizeof...(Tp) == 0
template <>
struct common_type<> {};
// bullet 2 - sizeof...(Tp) == 1
template <class Tp>
struct common_type<Tp> : public common_type<Tp, Tp> {};
// bullet 3 - sizeof...(Tp) == 2
// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
template <class Tp, class Up>
struct common_type<Tp, Up>
: std::conditional_t<std::is_same_v<Tp, std::decay_t<Tp>> && std::is_same_v<Up, std::decay_t<Up>>,
common_type2_imp<Tp, Up>,
common_type<std::decay_t<Tp>, std::decay_t<Up>>> {};
// bullet 4 - sizeof...(Tp) > 2
template <class Tp, class Up, class _Vp, class... Rest>
struct common_type<Tp, Up, _Vp, Rest...> : common_type_impl<common_types_tag<Tp, Up, _Vp, Rest...>> {};
template <class... Tp>
using common_type_t = typename common_type<Tp...>::type;
struct pinned {
pinned(int) {}
pinned(pinned&&) = delete;
pinned& operator=(pinned&&) = delete;
};
template<class... Ts>
concept has_common_type = requires { typename ::common_type_t<Ts...>; };
static_assert(std::is_same_v<::builtin_common_type_t<pinned, int>, pinned>);
static_assert(!has_common_type<pinned, int>);
Given the following type
std::common_type_t<pinned, int>shouldn't exist because none oftrue ? std::declval<pinned>() : std::declval<int>()andtrue ? std::declval<const pinned&>() : std::declval<const int&>()is well-formed ([meta.trans.other]/4).However, the implementation strategy using
__builtin_common_typegivespinned. Godbolt link.More expanded example:
Details