2016-04-12 2 views
3

Многие из помощников Boin's SFINAE появились в библиотеке std с C++ 11, но has_dereference, похоже, не имеет. Помимо этой функции, мне удалось устранить зависимость Boost от моего пакета, и я хотел бы полностью избавиться от нее, поэтому как лучше всего получить тот же эффект, используя только функции C++ 11 std?C++ 11-й эквивалент Boost has_dereference

+2

Разве вы не можете просто посмотреть на реализацию? –

+0

Я не знаю лицензию точно, но вы, вероятно, можете просто скопировать вставку реализации Boost в ваш код.Должен быть только заголовок и не слишком длинный. –

+0

@ Николь, я думаю, вы этого не сделали? ;-) Это делается с помощью скрытых (и сложных) # определений, таких как BOOST_TT_FORBIDDEN_IF, которые используются внутренним заголовком has_prefix_operator.hpp, а затем снова не определены. Так что нелегко перепроектировать и, разумеется, не просто копировать код из Boost в std-код. – andybuckley

ответ

6

Самый простой способ проверить, имеет ли класс какую-либо функцию без внешних зависимостей, как правило, с идиомой void_t.

// Define this once in your project somewhere accessible 
template <class ... T> 
using void_t = void; 

Трюк тогда всегда один и тот же; Вы определяете шаблон класса, который наследует от std::false_type:

template <class T, class = void> 
struct has_dereference : std::false_type {}; 

Это шаблон класса «запасной вариант». Теперь мы собираемся определить специализацию, которая работает только тогда, когда тип имеет свойство мы хотим:

template <class T> 
struct has_dereference<T, void_t<decltype(*std::declval<T>())>> : std::true_type {}; 

Чтобы использовать, просто сделать:

bool x = has_dereference<int*>::value; 
bool y = has_dereference<int>::value; 

т.д.

Добавлю что технически operator* на самом деле является семейством функций; оператор может быть квалифицированным как CV, так и квалифицированной категорией. Всякий раз, когда вы выполняете обнаружение по типу, вы фактически выполняете обнаружение в этом семействе. Я не буду подробно разбираться в деталях, потому что это редко встречается на практике (operator* редко относится к категории категории, и оператор почти всегда имеет версию const, а волатильность редко появляется), но стоит знать, если вы увидите что-то удивительное ,

Этот метод стоит знать, особенно если вы выполняете метапрограммирование без зависимостей, таких как Boost или Hana. Вы можете узнать больше о void_t здесь: How does `void_t` work.

+1

Работает хорошо. Спасибо! – andybuckley

4

Это аккуратный маленький помощник по написанию стилей SFINAE. Он использует std::void_t, который вы можете переопределить, если вам не хватает.

namespace details { 
    template<template<class...>class Z, class v, class...Ts> 
    struct can_apply:std::false_type{}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply=typename details::can_apply<Z, void, Ts...>::type; 

Как только у вас это будет, ваша проблема будет легкой.

template<class T> 
using deref_result = decltype(*std::declval<T>()); 

template<class T> 
using can_deref = can_apply<deref_result, T>; 

Идея заключается в том, чтобы скрыть std::void_t машины. Вы пишете черту, выражающую «результат некоторых вычислений», и из этого мы можем получить «это правильное вычисление».

Очень портативный void_t выглядит следующим образом:

namespace details { 
    template<class...>struct voider{using type=void;}; 
} 
template<class...Ts> 
using void_t=typename voider<Ts...>::type; 

делает это в одной строке разрушает некоторые старые компиляторы, а версия 2 линии достаточно легко, могли бы также.

0

Модифицированная версия Yakk «s:

template <class...> struct pack {}; 

namespace detail { 
    template<template <class...> class Z, class Pack, class = void> 
    struct can_apply_impl : std::false_type {}; 

    template<template<class...>class Z, class...Ts> 
    struct can_apply_impl<Z, pack<Ts...>, std::void_t<Z<Ts...>> > : std::true_type {}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply = detail::can_apply_impl<Z, pack<Ts...>>; 

DEMO

+0

ах, у меня была опечатка. Исправлено, я думаю! – Yakk

+0

@ Як подтвержден. –

+0

На самом деле это не новый ответ, это скорее комментарий к Якку о том, что у него была опечатка? – Barry

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