Как получить доступ к возможно более совершенному псевдониму типа в С++ 11?
Я хотел бы написать что-то вроде этого:
template <class T>
using MyTypeOrTupple = typename std::conditional<has_member_type_MyType<T>::value,
typename T::MyType,
std::tuple<> >::type;
Я реализовал has_member_type_MyType
, используя https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector
Однако GCC (4.8.4) все еще жалуется на использование T::MyType
, когда MyType
не определено в T
. Есть ли способ решить это?
Ответы
Ответ 1
template <typename...>
struct voider { using type = void; };
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename, typename = void_t<>>
struct MyTypeOrTupple { using type = std::tuple<>; };
template <typename T>
struct MyTypeOrTupple<T, void_t<typename T::MyType>> { using type = typename T::MyType; };
template <typename T>
using MyTypeOrTupple_t = typename MyTypeOrTupple<T>::type;
DEMO
Ответ 2
Не используйте эту сумасшедшую вещь из Викиучебников.
template <class T>
using MyType_t = typename T::MyType;
template<class T>
using MyTypeOrTuple = detected_or_t<std::tuple<>, MyType_t, T>;
Где detected_or_t
std::experimental::detected_or_t
из основ библиотеки TS v2 и может быть реализовано следующим образом:
namespace detail {
template<class...> struct voidify { using type = void; };
template<class...Ts> using void_t = typename voidify<Ts...>::type;
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template< class Default, template<class...> class Op, class... Args >
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
Ответ 3
Я думаю, для этого потребовалось 2 уровня косвенности:
template<typename ...>
struct void_type
{
using type = void;
};
template<typename ...T>
using void_t = typename void_type<T...>::type;
#define HAS_TYPE(NAME) \
template<typename, typename = void> \
struct has_type_##NAME: std::false_type \
{}; \
template<typename T> \
struct has_type_##NAME<T, void_t<typename T::NAME>>: std::true_type \
{}
HAS_TYPE(MyType);
template<typename T, bool = has_type_MyType<T>::value>
struct MyTypeOrTupple_impl;
template<typename T>
struct MyTypeOrTupple_impl<T, true>
{ using type = typename T::MyType; };
template<typename T>
struct MyTypeOrTupple_impl<T, false>
{ using type = std::tuple<>; };
template<typename T> using MyTypeOrTupple = typename MyTypeOrTupple_impl<T>::type;
DEMO
Ответ 4
Сохранение версии std::conditional
:
template <typename T> struct identity { using type = T; };
template <typename T> struct MyType { using type = typename T::MyType; };
template <class T>
using MyTypeOrTupple =
typename std::conditional<has_member_type_MyType<T>::value,
MyType<T>,
identity<std::tuple<>>>::type::type;