Шаблонный предикат класса шаблона не работает при частичной специализации - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть много EnableIf черт, которые в основном проверяют, удовлетворяет ли тип ввода интерфейсу.Я пытался создать общую черту Resolve, которую можно использовать для ее преобразования в логическую черту.

Примерно так - https://wandbox.org/permlink/ydEMyErOoaOa60Jx

template <
  template <typename...> class Predicate,
  typename T,
  typename = std::void_t<>>
struct Resolve : std::false_type {};
template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, Predicate<T>> : std::true_type {};

Теперь, если у вас есть черта EnableIf, такая как

template <typename T>
using EnableIfHasFoo = std::void_t<decltype(std::declval<T>().foo())>;

Вы можете создать булеву версию этогоочень быстро

template <typename T>
struct HasFoo : Resolve<EnableIfHasFoo, T> {};

Или аналогичный шаблон переменной.

Но по какой-то причине частичная специализация работает не так, как ожидалось.Решение не работает, как задумано.Смотрите вывод здесь - https://wandbox.org/permlink/ydEMyErOoaOa60Jx. То же, что реализовано "вручную", работает - https://wandbox.org/permlink/fmcFT3kLSqyiBprm

Я прибегаю к ручному определению типов самостоятельно.Есть ли какая-то деталь с частичными специализациями и аргументами шаблона, которую мне не хватает?

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Причина, по которой ваш подход потерпит неудачу, заключается в том, что Predicate<T>> в третьем параметре шаблона представляет собой , а не не выводимый контекст.Это приводит к непосредственному отказу в выводе (см. [temp.alias] / 2 ) вместо использования аргументов выведенного шаблона из других источников, как в не выводимом контексте.

Вы можете перенестиваш Predicate<T>> в не выведенный контекст, чтобы заставить его работать:

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

template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, typename identity<Predicate<T>>::type> : std::true_type {};

Live Demo

Потому что в невыбранном контексте вычет выиграл 'Это может произойти для Predicate<T> части, вместо этого он будет использовать Predicate и T, полученные из других источников.

Что касается обычного определения обнаружения (см. Ответ Гийома Рашико ) будет работать, потому что std::void_t в качестве псевдонима шаблона будет заменен на void в фазе удержания (см. [temp.alias] / 2 ), таким образом, нетпроизойдет удержание.

Вот несколько примеров, чтобы проиллюстрировать это более четко:

template<class T>
using always_int = int;

template<template<class> class TT>
struct deductor {};

template<template<class> class TT, class T>
void foo(T, deductor<TT>) {}

template<template<class> class TT, class T>
void bar(T, deductor<TT>, TT<T>) {}

template<class T>
void baz(T, always_int<T>) {}

int main() {
    // ok, both T and TT are deduced
    foo(0, deductor<always_int>{});

    // ERROR, TT<T> is NOT a non-deduced context, deduction failure
    bar(0, deductor<always_int>{}, 0);

    // ok, T is deduced, always_int<T> is replaced by int so no deduction
    baz(0, 0);
}
0 голосов
/ 28 ноября 2018

Я не могу найти точную причину, по которой ваш пример не работает.Если вы хотите углубиться в детали std::void_t, вот интересное объяснение

Даже если я не могу объяснить это подробно, я хотел бы добавить еще один надежный синтаксис, который используетсяв идиоме обнаружения .

template<
    template <typename...> class Predicate,
    typename T,
    typename = void>
struct Resolve : std::false_type {};

template <template <typename...> class Predicate, typename T>
struct Resolve<Predicate, T, std::void_t<Predicate<T>>> : std::true_type {};

template <typename T>
using EnableIfHasFoo = decltype(std::declval<T>().foo());

в реальном времени на проводнике компилятора

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...