Шаблоны условных псевдонимов

В таком типе, как неспециализированная структура шаблона pointer_traits (т. е. template <class Ptr> struct pointer_traits), существует шаблон псевдонима-члена rebind, который определяется как Ptr::rebind<U>, если он существует, или какой-либо другой тип в противном случае. Хотя я видел несколько ответов на проверку существования определенного члена, как реализовать шаблон "условного" псевдонима, такой как pointer_traits::rebind? То есть как бы следующим псевдо-С++:

template <typename T> using type = has_type<T::U> ? int : float;

or

template <typename T> using type = if_has_type<T::U, int, float>::type;

Я подумал об использовании чего-то вроде метода, описанного на https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector (раздел «Определение типов членов»), но я не знаю, как реализовать вспомогательную структуру, [единственный] тип члена которой зависит от существования другого типа члена.


person Mona the Monad    schedule 18.01.2017    source источник


Ответы (2)


Используя std::conditional из <type_traits>. Это так же просто, как:

using type = typename std::conditional<bool, int, float>::type;

or

using type = std::conditional_t<bool, int, float>;

где вы заменяете bool некоторым условием, оцениваемым во время компиляции до логического значения. В этом случае условием является проверка существующего члена.

Если условие true, тип становится псевдонимом int, иначе float.

ПОЛНЫЙ ПРИМЕР (Проверьте, является ли difference_type типом члена.)

namespace detail {

template<class Ptr>
using ptrait_diff = typename Ptr::difference_type;

template<class Ptr, bool = is_detected<ptrait_diff, Ptr>::value>
struct ptrait_diff_t { 
    using type = ptrdiff_t;
};

template<class Ptr>
struct ptrait_diff_t<Ptr, true> {
    using type = typename Ptr::difference_type;
};

} // namespace detail

а потом:

template<class Ptr>
struct pointer_traits
{
    using difference_type = typename detail::ptrait_diff_t<Ptr>::type;
};

Реализацию is_detected можно найти ЗДЕСЬ.

person DeiDei    schedule 18.01.2017
comment
Я думаю, что оператора больше интересует, как будет выглядеть условие, а не std::conditional - person WorldSEnder; 18.01.2017
comment
Реализация std::conditional кажется простой для понимания, но как работает is_detected? Кроме того, хотя я поклонник новых возможностей C++17, pointer_traits был реализован в C++11. Без использования [экспериментальных] функций С++ 17, как бы это реализовать? - person Mona the Monad; 18.01.2017
comment
@AliciaRose Как бы это реализовать без использования [экспериментальных] функций C++17? Уродливо и мучительно. Исходный код стандартной библиотеки можно найти в Интернете. - person DeiDei; 18.01.2017
comment
std::is_detected присутствует в С++ 17 Нет. using difference_type = conditional_t<is_detected<detail::ptrait_diff, Ptr>::value, typename Ptr::difference_type, ptrdiff_t>; Дважды нет. Вы не можете пытаться получить доступ к typename Ptr::difference_type, пока не узнаете, что он существует. И если вы пытаетесь использовать идиому обнаружения, это пример использования учебника для detected_or, а не is_detected. - person T.C.; 18.01.2017
comment
@Т.С. Верно. Спасибо, что заметили. Я ничего из этого не тестировал. По какой-то причине я был уверен, что std::is_detected стал стандартом. Разочаровываешься каждый день... - person DeiDei; 18.01.2017

Это проблема, для решения которой предназначен std::conditional.

#include <type_traits>
template<bool condition> 
using type = std::conditional_t<condition, int, float>;

static_assert(std::is_same<type<true>,  int>::value,   "type<true> should be int");
static_assert(std::is_same<type<false>, float>::value, "type<false> should be float");
person François Andrieux    schedule 18.01.2017