From 8ef99e888ddbef659c85614fec16572c2fb465a2 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 1 Feb 2022 10:31:40 -0700 Subject: [PATCH] Replace is_detected (type) by is_supported_operation (variable). Also provide a bunch of doc strings for the involved functions. Then also replace all of the current uses of the is_detected type by constexpr variables. --- include/deal.II/base/template_constraints.h | 112 +++++++++++--- include/deal.II/lac/la_parallel_vector.h | 48 +++--- include/deal.II/lac/precondition.h | 143 +++++++++--------- include/deal.II/matrix_free/fe_evaluation.h | 8 +- include/deal.II/matrix_free/matrix_free.h | 121 +++++++-------- include/deal.II/matrix_free/type_traits.h | 46 +++--- .../matrix_free/vector_access_internal.h | 29 ++-- 7 files changed, 278 insertions(+), 229 deletions(-) diff --git a/include/deal.II/base/template_constraints.h b/include/deal.II/base/template_constraints.h index 915732c084..1d0e3b4ba2 100644 --- a/include/deal.II/base/template_constraints.h +++ b/include/deal.II/base/template_constraints.h @@ -27,28 +27,49 @@ DEAL_II_NAMESPACE_OPEN -// Detection idiom from Version 2 of the C++ Extensions for Library +// Detection idiom adapted from Version 2 of the C++ Extensions for Library // Fundamentals, ISO/IEC TS 19568:2017 namespace internal { + /** + * A namespace used to declare the machinery for detecting whether a specific + * class supports an operation. This approach simulates C++20-style + * concepts with language standards before C++20. + */ namespace SupportsOperation { template using void_t = void; - // primary template handles all types not supporting the archetypal Op + /** + * The primary template class used in detecting operations. If the + * compiler does not choose the specialization, then the fall-back + * case is this general template, which then declares member variables + * and types according to the failed detection. + */ template class Op, - class... /*Args*/> + class... Args> struct detector { using value_t = std::false_type; using type = Default; }; - // specialization recognizes and handles only types supporting Op + /** + * A specialization of the general template. + * + * The trick this class uses is that, just like the general template, + * its second argument is always `void`, but here it is written as + * `void_t>` and consequently the compiler will only select this + * specialization if `Op` is in fact a valid type. This means that + * the operation we seek to understand is indeed supported. + * + * This specialization then declares member variables and types according + * to the successful detection. + */ template class Op, class... Args> struct detector>, Op, Args...> { @@ -57,10 +78,17 @@ namespace internal }; - // base class for nonesuch to inherit from so it is not an aggregate + /** + * A base class for the `nonesuch` type to inherit from so it is not an + * aggregate. + */ struct nonesuch_base {}; + /** + * A type that can not be used in any reasonable way and consequently + * can be used to indicate a failed detection in template metaprogramming. + */ struct nonesuch : private nonesuch_base { ~nonesuch() = delete; @@ -69,29 +97,64 @@ namespace internal operator=(nonesuch const &) = delete; }; - } // namespace SupportsOperation + template class Op, class... Args> + using detected_or = detector; - template class Op, class... Args> - using detected_or = - internal::SupportsOperation::detector; + template