Подтвердить что ты не робот

Как получить доступ к возможно более совершенному псевдониму типа в С++ 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. Есть ли способ решить это?

4b9b3361

Ответ 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;