|
@@ -55,7 +55,117 @@ namespace meta { |
|
|
template <typename...> using void_t = void;
|
|
|
template <typename...> using void_t = void;
|
|
|
#endif
|
|
|
#endif
|
|
|
//! @}
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Not a type to use in detected idiom
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct nat_ {
|
|
|
|
|
|
nat_() = delete;
|
|
|
|
|
|
~nat_() = delete;
|
|
|
|
|
|
nat_(nat_ const&) = delete;
|
|
|
|
|
|
void operator = (nat_ const&) = delete;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//! Detector for detection idiom
|
|
|
|
|
|
//! @{
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
template <typename Default,
|
|
|
|
|
|
typename AlwaysVoid,
|
|
|
|
|
|
template<typename...> class Op, typename... Args>
|
|
|
|
|
|
struct detector {
|
|
|
|
|
|
using detected = false_;
|
|
|
|
|
|
using type = Default;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Default,
|
|
|
|
|
|
template<typename...> class Op, typename... Args>
|
|
|
|
|
|
struct detector <Default, void_t<Op<Args...>>, Op, Args...> {
|
|
|
|
|
|
using detected = true_;
|
|
|
|
|
|
using type = Op<Args...>;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//! helper for detected_or_t
|
|
|
|
|
|
template <typename Default,
|
|
|
|
|
|
template<typename...> class Op, typename... Args>
|
|
|
|
|
|
using detected_or = detector<Default, void, Op, Args...>;
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* detection interface
|
|
|
|
|
|
*/
|
|
|
|
|
|
//! @{
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Checks if Op<Args...> is a valid expression without evaluating it.
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param Op a meta-callback function to pass Args...
|
|
|
|
|
|
* \param Args... types to pass to Op for checking
|
|
|
|
|
|
* \return status of the operation [bool_]
|
|
|
|
|
|
* \arg true_ if Op<Args...> is valid expression
|
|
|
|
|
|
* \arg false_ if Op<Args...> is not valid
|
|
|
|
|
|
*
|
|
|
|
|
|
* \example
|
|
|
|
|
|
* \code
|
|
|
|
|
|
* // archetypal alias for a copy assignment operation
|
|
|
|
|
|
* template< class T >
|
|
|
|
|
|
* using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
|
|
|
|
|
|
*
|
|
|
|
|
|
* template< class T >
|
|
|
|
|
|
* using is_copy_assignable = is_detected< T, copy_assign_t >;
|
|
|
|
|
|
* \endcode
|
|
|
|
|
|
*/
|
|
|
|
|
|
template <template<typename...> class Op, typename... Args>
|
|
|
|
|
|
using is_detected = typename detail::detector<nat_, void, Op, Args...>::detected;
|
|
|
|
|
|
|
|
|
|
|
|
//! Detection predicate
|
|
|
|
|
|
template< template<typename...> class Op, typename... Args>
|
|
|
|
|
|
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
|
|
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
* Detection idiom toolkit
|
|
|
|
|
|
*/
|
|
|
|
|
|
//! @{
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to evaluation of Op<Args...> if it's valid and to nat_ if not
|
|
|
|
|
|
template <template<typename...> class Op, typename... Args>
|
|
|
|
|
|
using detected_t = eval <
|
|
|
|
|
|
detail::detector<nat_, void, Op, Args...>
|
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to evaluation of Op<Args...> if it's valid and to \p Default if not
|
|
|
|
|
|
template <typename Default,
|
|
|
|
|
|
template<typename...> class Op, typename... Args>
|
|
|
|
|
|
using detected_or_t = eval <
|
|
|
|
|
|
detail::detected_or<Default, Op, Args...>
|
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to true_ if evaluation of Op<Args...> is \p Expected and to false_ if not
|
|
|
|
|
|
template <typename Expected,
|
|
|
|
|
|
template<typename...> class Op, typename... Args >
|
|
|
|
|
|
using is_detected_exact = same_<Expected, detected_t<Op, Args...> >;
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
|
|
|
|
|
|
template <typename Expected,
|
|
|
|
|
|
template<typename...> class Op, typename... Args >
|
|
|
|
|
|
constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to true_ if evaluation of Op<Args...> is convertible to \p To
|
|
|
|
|
|
//! and to false_ if not
|
|
|
|
|
|
template <typename To,
|
|
|
|
|
|
template<typename...> class Op, typename... Args >
|
|
|
|
|
|
using is_detected_convertible = std::is_convertible< detected_t<Op, Args...>, To >;
|
|
|
|
|
|
|
|
|
|
|
|
//! evaluates to true if evaluation of Op<Args...> is convertible to \p To
|
|
|
|
|
|
//! and to false if not
|
|
|
|
|
|
template <typename To,
|
|
|
|
|
|
template<typename...> class Op, typename... Args >
|
|
|
|
|
|
constexpr bool is_detected_convertible_v =
|
|
|
|
|
|
is_detected_convertible<To, Op, Args...>::value;
|
|
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
}}
|
|
|
}}
|
|
|
//!@}
|
|
|
//!@}
|
|
|
|
|
|
|
|
|
#endif /* __utl_meta_void_h__ */
|
|
|
|
|
|
|
|
|
#endif /* __utl_meta_detection_h__ */
|