Можно ли построить метафункцию lazy_conditional

Предположим, я хочу использовать std::conditional определить тип, если тип vector<...> возвращение будет vector<...>::size_type а если нет то будет int, (просто пример).

Наивный способ использования std::conditional:

template<class V> struct is_vector : std::false_type{};
template<class T> struct is_vector<std::vector<T>> : std::true_type{};

template<class C>
using my_size_type = typename std::conditional<
not is_vector<C>::value,
int,
C::size_type // note that this line only makes sense when condition is false
>::type;

Однако это не удается, потому что если C это сказать double, double::size_type выдаст ошибку, даже если это оценка второй ложной опции.

Итак, мне интересно, если есть lazy_conditional в котором ложное (или второе ложное) утверждение не оценивается.

Я нашел кое-что здесь: https://stackoverflow.com/a/5317659/225186 но я не знаю, как использовать это мой пример.


Обратите внимание, что я знаю, как получить тот же результат без использования std::conditional:

template<class V> struct my_size_type{typedef int type;};
template<class T> struct my_size_type<std::vector<T>>{typedef std::vector<T>::size_type type;};

Вопрос в том, есть ли lazy_conditional что-то инкапсулировало std::conditional это короткое замыкание.


После некоторой пробной ошибки мне удается использовать идеи в https://stackoverflow.com/a/5317659/225186 и получить к этому следующее. Это также заставляет меня думать, что это не возможно, чтобы написать std::lazy_conditional так как C::size_type не может появляться вообще ни в одном выражении априори, поэтому необходимы двухэтапные выражения.

template<class C, bool B> struct false_case{
typedef void type;
};
template<class C> struct false_case<C, false>{
typedef typename C::size_type type;
};

template<class C>
using size_type = typename std::conditional<
not is_vector<C>::value,
int,
typename false_case<C, not is_vector<C>::value>::type
>::type;

Я даже не мог сжать это в макрос, потому что каждый случай индивидуален.

5

Решение

Вам нужен уровень косвенности.

template<class T> struct identity { using type = T; };

template<class C>
struct size_type_of : identity<typename C::size_type> { };

template<class C>
using size_type = typename std::conditional<not is_vector<C>::value,
identity<int>,
size_type_of<C>>::type::type;

Дело в том, чтобы отложить рассмотрение C::size_type (путем создания size_type_of<C>), пока вы не знаете, что есть.


Если то, что вы действительно хотите сделать, этоC::size_type если он существует, int иначе «, то std::experimental::detected_or_t твой друг:

template<class C>
using size_type_t = typename C::size_type;

template<class C>
using size_type_or_default = std::experimental::detected_or_t<int, size_type_t, C>;
4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]