2017-01-06 2 views
3

У меня разные вид типы, каждый из которых имеет постоянную константу std::size_t View::dimension и тип члена typename View::value_type.SFINAE внутри std :: аргумент enable_if

Следующая проверка компиляции типа должны проверить, если оба From и To являются видами (проверено с помощью is_view<>), а содержание From может быть назначен To. (такие же размеры и типы конвертируемых значений).

template<typename From, typename To> 
struct is_compatible_view : std::integral_constant<bool, 
    is_view<From>::value && 
    is_view<To>::value && 
    From::dimension == To::dimension && 
    std::is_convertible<typename From::value_type, typename To::value_type>::value 
> { }; 

is_view<T> таков, что она всегда имеет значение std::true_type или std::false_type для любого типа T. Проблема заключается в том, что если From или To не является типом вида, то From::dimension (например) может не существовать, а is_compatible_view<From, To> вызывает ошибку компиляции. В этом случае вместо этого следует оценить std::false_type.

is_compatible_view используется для SFINAE с std::enable_if, чтобы отключить функции-члены. Например, класс представления может иметь функцию-член

struct View { 
    constexpr static std::size_t dimension = ... 
    using value_type = ... 

    template<typename Other_view> 
    std::enable_if_t<is_compatible_view<Other_view, View>> assign_from(const Other_view&); 

    void assign_from(const Not_a_view&); 
}; 

Not_a_view не вид и вызывает ошибку компиляции в is_compatible_view<Not_a_view, ...>. При вызове view.assign_from(Not_a_view()) SFINAE не применяется, и вместо этого возникает ошибка компиляции, когда компилятор пытается разрешить первую функцию assign_from.

Как можно написать is_compatible_view, чтобы это работает правильно? В C++ 17 std::conjunction<...> разрешить это?

ответ

4

Один подход использует что-то вроде std::conditional, чтобы отложить оценку некоторых частей вашего черта вашего типа, пока мы не проверим, что другие части вашего черта вашего типа уже верны.

То есть:

// this one is only valid if From and To are views 
template <class From, class To> 
struct is_compatible_view_details : std::integral_constant<bool, 
    From::dimension == To::dimension && 
    std::is_convertible<typename From::value_type, typename To::value_type>::value 
> { };   

// this is the top level one 
template<typename From, typename To> 
struct is_compatible_view : std::conditional_t< 
    is_view<From>::value && is_view<To>::value, 
    is_compatible_view_details<From, To>, 
    std::false_type>::type 
{ }; 

Обратите внимание, что я использую как conditional_t и ::type. is_compatible_view_details будет отображаться только в том случае, если оба изображения From и To являются видами.


Аналогичный подход должен был бы использовать std::conjunction с вышесказанным, что из-за короткого замыкания будет так же задержит оценка:

template <class From, class To> 
struct is_compatible_view : std::conjunction_t< 
    is_view<From>, 
    is_view<To>, 
    is_compatible_view_details<From, To> 
    > 
{ }; 

В любом случае, вы должны вытащить детали.


Третий подход заключается в использовании enable_if_t в качестве специализации:

template <class From, class To, class = void> 
struct is_compatible_view : std::false_type { }; 

template <class From, class To> 
struct is_compatible_view<From, To, std::enable_if_t< 
    is_view<From>::value && 
    is_view<To>::value && 
    From::dimension == To::dimension && 
    std::is_convertible<typename From::value_type, typename To::value_type>::value>> 
: std::true_type { }; 

Здесь, если какой-либо из выражений в enable_if_t плохо сформированы, SFINAE пинает, и мы просто использовать основной шаблон, который равен false_type.

+0

На самом деле я действительно не вижу смысла ':: type' в вашем первом фрагменте.Кроме того, в зависимости от варианта использования может быть достаточно создать шаблон-шаблон «enable_if_compatible_view», который просто вытащил бы любые ошибки в «From :: value_type» и т. Д. В непосредственный контекст. –

Смежные вопросы