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