Многие из помощников Boin's SFINAE появились в библиотеке std с C++ 11, но has_dereference
, похоже, не имеет. Помимо этой функции, мне удалось устранить зависимость Boost от моего пакета, и я хотел бы полностью избавиться от нее, поэтому как лучше всего получить тот же эффект, используя только функции C++ 11 std?C++ 11-й эквивалент Boost has_dereference
ответ
Самый простой способ проверить, имеет ли класс какую-либо функцию без внешних зависимостей, как правило, с идиомой 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.
Работает хорошо. Спасибо! – andybuckley
Это аккуратный маленький помощник по написанию стилей 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 линии достаточно легко, могли бы также.
Модифицированная версия 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...>>;
- 1. C# эквивалент boost :: gregorian generators
- 2. boost :: связать эквивалент в C?
- 3. unique_ptr boost эквивалент?
- 4. C++ boost :: lambda :: ret эквивалент в phoenix
- 5. pybind11 эквивалент boost :: python :: extract?
- 6. Тип безопасного boost :: property_tree эквивалент
- 7. Boost :: эквивалент графика для java?
- 8. Есть ли эквивалент Boost :: Python для Java?
- 9. boost :: next и std :: следующий эквивалент?
- 10. Есть ли boost :: shared_ptr <T> эквивалент в C#?
- 11. Есть ли эквивалент C# для boost :: interprocess :: basic_string?
- 12. Есть ли эквивалент boost :: timer :: cpu_timer в C#?
- 13. std :: lock() эквивалент для boost :: shared_mutex?
- 14. Эквивалент защитников CppUnit для boost :: test?
- 15. Эквивалент Regex.Replace in C++
- 16. Boost :: эквивалент tuple для элемента управления Python?
- 17. Qt умный указательный эквивалент boost :: shared_array?
- 18. SWIG эквивалент хранения boost :: python :: object
- 19. C++ Boost bind value type
- 20. C++ эквивалент C fgets
- 21. C эквивалент C++ cin.peek()
- 22. C# эквивалент C++ mem_fun?
- 23. C# эквивалент C sscanf
- 24. C эквивалент STL C++
- 25. C++ non intrusive boost serialization boost :: smart_ptr
- 26. C++/boost аналог C# BlockingCollection?
- 27. C++ - boost :: любая сериализация
- 28. C++ Boost program_options crash
- 29. Boost C++ - точки входа?
- 30. C++ boost lambda libraries
Разве вы не можете просто посмотреть на реализацию? –
Я не знаю лицензию точно, но вы, вероятно, можете просто скопировать вставку реализации Boost в ваш код.Должен быть только заголовок и не слишком длинный. –
@ Николь, я думаю, вы этого не сделали? ;-) Это делается с помощью скрытых (и сложных) # определений, таких как BOOST_TT_FORBIDDEN_IF, которые используются внутренним заголовком has_prefix_operator.hpp, а затем снова не определены. Так что нелегко перепроектировать и, разумеется, не просто копировать код из Boost в std-код. – andybuckley