Как работает черта when <> в boost.Hana? - PullRequest
0 голосов
/ 09 июня 2018

У меня есть некоторый опыт работы с std::enable_if.IIRC, речь идет о том, что если правильно сформированное выражение приводит к true возвращению пользовательского типа T (если он задан) или void через псевдоним вложенного типа.

template<bool,typename = void>
struct enable_if;

template<typename T>
struct enable_if<true,T>{
 using type = T;
};

template <typename T, typename = void>
struct base_template{
     enum { value= false};
};

template <typename T>
struct base_template<T, typename enable_if<std::is_integral<T>::value>::type> {
    enum { value= true};// something useful...
};

struct some{};
static_assert(base_template<some>::value,"F*"); //error: static assertion failed: F
static_assert(base_template<int>::value,"F*");

Но в boost.Hana я вижу эточерта когда <> и ее реализация похожа на

template <bool condition>
struct when;

template <typename T, typename = when<true>>
struct base_template{
     enum { value= false};
};

template <typename T>
struct base_template<T, when<std::is_integral<T>::value>> {
    enum { value= true};// something useful...
};

struct some{};

static_assert(base_template<int>::value,"F*");
static_assert(base_template<some>::value,"F*");<source>:28:15: error: static assertion failed: F*

Как здесь работает SFINAE?хотя std::is_integral<some>::value приведет к ложному результату, это не значит (да?), что when<false> равен ill-formed и должен отправить экземпляр в шаблон первичного класса.Я что-то здесь упускаю?

1 Ответ

0 голосов
/ 10 июня 2018

Это та же самая общая идея.Вы можете использовать enable_if_t или decltype в основном таким же образом.Теперь вы, вероятно, привыкли видеть частичные специализации SFINAE, например:

template<class T, class U = void>
struct Foo {};

template<class T>
struct Foo<T, decltype(T::bar())> {};

... Foo<X> ...

Здесь компилятор Foo<X> сначала расширяется до Foo<X, void> (потому что вы не указали U в«сайт вызова», поэтому вместо него указывается значение по умолчанию U = void).Затем компилятор ищет наиболее подходящую специализацию шаблона класса Foo.Если decltype(X::bar()) на самом деле void, то Foo<T, decltype(T::bar())> [with T=X] будет идеально соответствовать Foo<X, void>.В противном случае вместо него будет использоваться универсальный Foo<T, U> [with T=X, U=void].

Теперь для примера Hana when.

template<bool> struct when {};

template<class T, class U = when<true>>
struct Foo {};

template<class T>
struct Foo<T, when<T::baz>> {};

... Foo<X> ...

Здесь Foo<X> сначала расширяется компилятором до Foo<X, when<true>> (потому что вы не указали U на «сайте вызова», поэтому вместо него введено значение по умолчанию U = when<true>).Затем компилятор ищет наиболее подходящую специализацию шаблона класса Foo.Если when<X::baz> на самом деле when<true>, то Foo<T, when<T::baz>> [with T=X] идеально подойдет для Foo<X, when<true>>.В противном случае вместо него будет использоваться универсальный Foo<T, U> [with T=X, U=when<true>].

Вы можете заменить простое выражение T::baz в моем примере любым произвольно сложным логическим выражением, если оно может быть оценено в constexpr.В вашем исходном примере это выражение было std::is_integral<T>::value.

Моя сессия CppCon 2017 «Суп СФИНЫ» проходит через несколько похожих примеров.

...