From: Pedro Alves <pedro@palves.net>
To: gdb-patches@sourceware.org
Subject: [pushed v2 3/4] Rewrite valid-expr.h's internals in terms of the detection idiom (C++17/N4502)
Date: Mon, 14 Sep 2020 22:31:11 +0100 [thread overview]
Message-ID: <20200914213112.19593-4-pedro@palves.net> (raw)
In-Reply-To: <20200914213112.19593-1-pedro@palves.net>
An earlier attempt at doing this had failed (wouldn't work in GCCs
around 4.8, IIRC), but now that I try again, it works. I suspect that
my previous attempt did not use the pre C++14-safe void_t (in
traits.h).
I want to switch to this model because:
- It's the standard detection idiom that folks will learn starting
with C++17.
- In the enum_flags unit tests, I have a static_assert that triggers
a warning (resulting in build error), which GCC does not suppress
because the warning is not being triggered in the SFINAE context.
Switching to the detection idiom fixes that. Alternatively,
switching to the C++03-style expression-validity checking with a
varargs overload would allow addressing that, but I think that
would be going backwards idiomatically speaking.
- While this patch shows a net increase of lines of code, the magic
being added to traits.h can be removed in a few years when we start
requiring C++17.
gdbsupport/ChangeLog:
* traits.h (struct nonesuch, struct detector, detected_or)
(detected_or_t, is_detected, detected_t, detected_or)
(detected_or_t, is_detected_exact, is_detected_convertible): New.
* valid-expr.h (CHECK_VALID_EXPR_INT): Use gdb::is_detected_exact.
---
gdbsupport/ChangeLog | 7 ++++++
gdbsupport/traits.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
gdbsupport/valid-expr.h | 20 +++------------
3 files changed, 77 insertions(+), 17 deletions(-)
diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog
index 6cda6050f9..4858cc6b56 100644
--- a/gdbsupport/ChangeLog
+++ b/gdbsupport/ChangeLog
@@ -1,3 +1,10 @@
+2020-09-14 Pedro Alves <pedro@palves.net>
+
+ * traits.h (struct nonesuch, struct detector, detected_or)
+ (detected_or_t, is_detected, detected_t, detected_or)
+ (detected_or_t, is_detected_exact, is_detected_convertible): New.
+ * valid-expr.h (CHECK_VALID_EXPR_INT): Use gdb::is_detected_exact.
+
2020-09-10 Kamil Rytarowski <n54@gmx.com>
* eintr.h: New file.
diff --git a/gdbsupport/traits.h b/gdbsupport/traits.h
index 2a6f00654c..93b609ac10 100644
--- a/gdbsupport/traits.h
+++ b/gdbsupport/traits.h
@@ -52,6 +52,73 @@ struct make_void { typedef void type; };
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. */
diff --git a/gdbsupport/valid-expr.h b/gdbsupport/valid-expr.h
index b1c8446814..a22fa61134 100644
--- a/gdbsupport/valid-expr.h
+++ b/gdbsupport/valid-expr.h
@@ -58,26 +58,12 @@
#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
--
2.14.5
next prev parent reply other threads:[~2020-09-14 21:31 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-14 21:31 [pushed v2 0/4] Rewrite enum_flags, add unit tests, fix problems Pedro Alves
2020-09-14 21:31 ` [pushed v2 1/4] Use type_instance_flags more throughout Pedro Alves
2020-09-15 2:28 ` [pushed] gdb: remove TYPE_INSTANCE_FLAGS Simon Marchi
2020-09-15 21:28 ` Luis Machado
2020-09-16 2:50 ` Simon Marchi
2020-09-16 11:01 ` Pedro Alves
2020-09-16 20:44 ` Simon Marchi
2020-09-14 21:31 ` [pushed v2 2/4] Rename address_space_int_to_name/address_space_name_to_int Pedro Alves
2020-09-14 21:31 ` Pedro Alves [this message]
2020-09-17 10:57 ` [pushed v2 3/4] Rewrite valid-expr.h's internals in terms of the detection idiom (C++17/N4502) Vaseeharan Vinayagamoorthy
2020-09-17 11:41 ` Luis Machado
2020-09-17 16:10 ` Vaseeharan Vinayagamoorthy
2020-09-17 16:23 ` Luis Machado
2020-09-14 21:31 ` [pushed v2 4/4] Rewrite enum_flags, add unit tests, fix problems Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200914213112.19593-4-pedro@palves.net \
--to=pedro@palves.net \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox