dune-common  2.11
concept.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_COMMON_CONCEPT_HH
6 #define DUNE_COMMON_CONCEPT_HH
7 
8 #include <type_traits>
9 #include <utility>
10 #include <tuple>
11 
13 #include <dune/common/typelist.hh>
14 #include <dune/common/indices.hh>
15 
22 namespace Dune {
23 
33 namespace Concept {
34 
35 
36 
51 template<class... BaseConcepts>
52 struct Refines
53 {
54  typedef TypeList<BaseConcepts...> BaseConceptList;
55 };
56 
57 
58 #ifndef DOXYGEN
59 
60 namespace Impl {
61 
62  // #############################################################################
63  // # All functions following here are implementation details
64  // # for the models() function below.
65  // #############################################################################
66 
67  // Forward declaration
68  template<class C, class... T>
69  constexpr bool models();
70 
71 
72 
73  // Here is the implementation of the concept checking.
74  // The first two overloads do the magic for checking
75  // if the requirements of a concept are satisfied.
76  // The rest is just for checking base concepts in case
77  // of refinement.
78 
79  // This overload is present if type substitution for
80  // C::require(T...) is successful, i.e., if the T...
81  // matches the requirement of C. In this case this
82  // overload is selected because PriorityTag<1>
83  // is a better match for PrioriryTag<42> than
84  // PriorityTag<0> in the default overload.
85  template<class C, class... T,
86  decltype(std::declval<C>().require(std::declval<T>()...), 0) =0>
87  constexpr std::true_type matchesRequirement(PriorityTag<1>)
88  { return {}; }
89 
90  // If the above overload is ruled out by SFINAE because
91  // the T... does not match the requirements of C, then
92  // this default overload drops in.
93  template<class C, class... T>
94  constexpr std::false_type matchesRequirement(PriorityTag<0>)
95  { return {}; }
96 
97 
98 
99  // An empty list C of concepts is always matched by T...
100  template<class...T>
101  constexpr bool modelsConceptList(TypeList<>)
102  { return true; }
103 
104  // A nonempty list C0,..,CN of concepts is modeled
105  // by T... if it models the concept C0
106  // and all concepts in the list C1,..,CN.
107  template<class...T, class C0, class... CC>
108  constexpr bool modelsConceptList(TypeList<C0, CC...>)
109  { return models<C0, T...>() and modelsConceptList<T...>(TypeList<CC...>()); }
110 
111 
112 
113  // If C is an unrefined concept, then T... models C
114  // if it matches the requirement of C.
115  template<class C, class... T>
116  constexpr bool modelsConcept(PriorityTag<0>)
117  { return matchesRequirement<C, T...>(PriorityTag<42>()); }
118 
119  // If C is a refined concept, then T... models C
120  // if it matches the requirement of C and of
121  // all base concepts.
122  //
123  // This overload is used if C::BaseConceptList exists
124  // due to its higher priority.
125  template<class C, class... T,
126  decltype(typename C::BaseConceptList(), 0) = 0>
127  constexpr bool modelsConcept(PriorityTag<1>)
128  { return matchesRequirement<C, T...>(PriorityTag<42>()) and modelsConceptList<T...>(typename C::BaseConceptList()); }
129 
130  // This is the full concept check. It's defined here in the
131  // implementation namespace with 'constexpr bool' return type
132  // because we need a forward declaration in order to use it
133  // internally above.
134  //
135  // The actual interface function can then call this one and
136  // return the result as std::integral_constant<bool,*> which
137  // does not allow for a forward declaration because the return
138  // type is deduced.
139  template<class C, class... T>
140  constexpr bool models()
141  {
142  return modelsConcept<C, T...>(PriorityTag<42>());
143  }
144 
145 } // namespace Dune::Concept::Impl
146 
147 #endif // DOXYGEN
148 
149 } // namespace Dune::Concept
150 
151 
152 
182 template<class C, class... T>
183 constexpr auto models()
184 {
185  return std::bool_constant<Concept::Impl::models<C, T...>()>();
186 }
187 
188 
189 
190 namespace Concept {
191 
192 // #############################################################################
193 // # The method tupleEntriesModel() does the actual check if the types in a tuple
194 // # model a concept using the implementation details above.
195 // #############################################################################
196 
197 template<class C, class Tuple>
198 constexpr auto tupleEntriesModel()
199 {
200  return Dune::unpackIntegerSequence([&](auto... i) {
201  return std::conjunction<decltype(Dune::models<C, std::tuple_element_t<decltype(i)::value, Tuple>>())...>();
202  }, std::make_index_sequence<std::tuple_size_v<Tuple>>());
203 }
204 
205 // #############################################################################
206 // # The following require*() functions are just helpers that allow to
207 // # propagate a failed check as substitution failure. This is useful
208 // # inside of a concept definition.
209 // #############################################################################
210 
211 // Helper function for use in concept definitions.
212 // If the passed value b is not true, the concept will to be satisfied.
213 template<bool b, typename std::enable_if<b, int>::type = 0>
214 constexpr bool requireTrue()
215 {
216  return true;
217 }
218 
219 // Helper function for use in concept definitions.
220 template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
221 constexpr bool requireConcept()
222 {
223  return true;
224 }
225 
226 // Helper function for use in concept definitions.
227 // This allows to avoid using decltype
228 template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
229 constexpr bool requireConcept(T&&... /*t*/)
230 {
231  return true;
232 }
233 
234 // Helper function for use in concept definitions.
235 // This checks if the concept given as first type is modelled by all types in the tuple passed as argument
236 template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
238 {
239  return true;
240 }
241 
242 // Helper function for use in concept definitions.
243 // If the first passed type is not convertible to the second, the concept will not be satisfied.
244 template<class From, class To,
245  typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
246 constexpr bool requireConvertible()
247 {
248  return true;
249 }
250 
251 // Helper function for use in concept definitions.
252 // If passed argument is not convertible to the first passed type, the concept will not be satisfied.
253 template<class To, class From,
254  typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
255 constexpr bool requireConvertible(const From&)
256 {
257  return true;
258 }
259 
260 // Helper function for use in concept definitions.
261 // This will always evaluate to true. If just allow
262 // to turn a type into an expression. The failure happens
263 // already during substitution for the type argument.
264 template<typename T>
265 constexpr bool requireType()
266 {
267  return true;
268 }
269 
270 // Helper function for use in concept definitions.
271 // If first passed type is not a base class of second type, the concept will not be satisfied.
272 template<class Base, class Derived,
273  typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
274 constexpr bool requireBaseOf()
275 {
276  return true;
277 }
278 
279 // Helper function for use in concept definitions.
280 // If first passed type is not a base class of first arguments type, the concept will not be satisfied.
281 template<class Base, class Derived,
282  typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
283 constexpr bool requireBaseOf(const Derived&)
284 {
285  return true;
286 }
287 
288 // Helper function for use in concept definitions.
289 // If the passed types are not the same, the concept will not be satisfied.
290 template<class A, class B,
291  typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
292 constexpr bool requireSameType()
293 {
294  return true;
295 }
296 
297 
298 
299 } // namespace Dune::Concept
300 
301 } // namespace Dune
302 
303 
304 
305 
306 #endif // DUNE_COMMON_CONCEPT_HH
constexpr bool requireSameType()
Definition: concept.hh:292
constexpr auto tupleEntriesModel()
Definition: concept.hh:198
constexpr auto models()
Check if concept is modeled by given types.
Definition: concept.hh:183
decltype(auto) constexpr unpackIntegerSequence(F &&f, [[maybe_unused]] std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:124
constexpr bool requireTrue()
Definition: concept.hh:214
I i
Definition: hybridmultiindex.hh:328
constexpr bool requireConcept()
Definition: concept.hh:221
Dune namespace
Definition: alignedallocator.hh:12
Utilities for type computations, constraining overloads, ...
std::tuple< MetaType< T >... > TypeList
A simple type list.
Definition: typelist.hh:87
Helper class for tagging priorities.
Definition: typeutilities.hh:86
constexpr bool requireConceptForTupleEntries()
Definition: concept.hh:237
Base class for refined concepts.
Definition: concept.hh:52
constexpr bool requireType()
Definition: concept.hh:265
Helper class for tagging priorities.
Definition: typeutilities.hh:72
constexpr bool requireBaseOf()
Definition: concept.hh:274
TypeList< BaseConcepts... > BaseConceptList
Definition: concept.hh:54
constexpr bool requireConvertible()
Definition: concept.hh:246