template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
+/* Implementation of the detection idiom:
+
+ - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
+ - http://en.cppreference.com/w/cpp/experimental/is_detected
+
+*/
+
+struct nonesuch
+{
+ nonesuch () = delete;
+ ~nonesuch () = delete;
+ nonesuch (const nonesuch &) = delete;
+ void operator= (const nonesuch &) = delete;
+};
+
+namespace detection_detail {
+/* Implementation of the detection idiom (negative case). */
+template<typename Default, typename AlwaysVoid,
+ template<typename...> class Op, typename... Args>
+struct detector
+{
+ using value_t = std::false_type;
+ using type = Default;
+};
+
+/* Implementation of the detection idiom (positive case). */
+template<typename Default, template<typename...> class Op, typename... Args>
+struct detector<Default, void_t<Op<Args...>>, Op, Args...>
+{
+ using value_t = std::true_type;
+ using type = Op<Args...>;
+};
+
+/* Detect whether Op<Args...> is a valid type, use Default if not. */
+template<typename Default, template<typename...> class Op,
+ typename... Args>
+using detected_or = detector<Default, void, Op, Args...>;
+
+/* Op<Args...> if that is a valid type, otherwise Default. */
+template<typename Default, template<typename...> class Op,
+ typename... Args>
+using detected_or_t
+ = typename detected_or<Default, Op, Args...>::type;
+
+} /* detection_detail */
+
+template<template<typename...> class Op, typename... Args>
+using is_detected
+ = typename detection_detail::detector<nonesuch, void, Op, Args...>::value_t;
+
+template<template<typename...> class Op, typename... Args>
+using detected_t
+ = typename detection_detail::detector<nonesuch, void, Op, Args...>::type;
+
+template<typename Default, template<typename...> class Op, typename... Args>
+using detected_or = detection_detail::detected_or<Default, Op, Args...>;
+
+template<typename Default, template<typename...> class Op, typename... Args>
+using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+template<typename Expected, template<typename...> class Op, typename... Args>
+using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
+
+template<typename To, template<typename...> class Op, typename... Args>
+using is_detected_convertible
+ = std::is_convertible<detected_t<Op, Args...>, To>;
+
/* A few trait helpers, mainly stolen from libstdc++. Uppercase
because "and/or", etc. are reserved keywords. */
#define CHECK_VALID_EXPR_INT(TYPENAMES, TYPES, VALID, EXPR_TYPE, EXPR) \
namespace CONCAT (check_valid_expr, __LINE__) { \
\
- template<typename, typename, typename = void> \
- struct is_valid_expression \
- : std::false_type {}; \
- \
template <TYPENAMES> \
- struct is_valid_expression<TYPES, gdb::void_t<decltype (EXPR)>> \
- : std::true_type {}; \
+ using archetype = decltype (EXPR); \
\
- static_assert (is_valid_expression<TYPES>::value == VALID, \
+ static_assert (gdb::is_detected_exact<EXPR_TYPE, \
+ archetype, TYPES>::value == VALID, \
""); \
- \
- template<TYPENAMES, typename = void> \
- struct is_same_type \
- : std::is_same<EXPR_TYPE, void> {}; \
- \
- template <TYPENAMES> \
- struct is_same_type<TYPES, gdb::void_t<decltype (EXPR)>> \
- : std::is_same<EXPR_TYPE, decltype (EXPR)> {}; \
- \
- static_assert (is_same_type<TYPES>::value, ""); \
} /* namespace */
/* A few convenience macros that support expressions involving a