Dune Core Modules (unstable)

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>
15 #include <dune/common/std/type_traits.hh>
16 
23 namespace Dune {
24 
34 namespace Concept {
35 
36 
37 
52 template<class... BaseConcepts>
53 struct Refines
54 {
55  typedef TypeList<BaseConcepts...> BaseConceptList;
56 };
57 
58 
59 #ifndef DOXYGEN
60 
61 namespace Impl {
62 
63  // #############################################################################
64  // # All functions following here are implementation details
65  // # for the models() function below.
66  // #############################################################################
67 
68  // Forward declaration
69  template<class C, class... T>
70  constexpr bool models();
71 
72 
73 
74  // Here is the implementation of the concept checking.
75  // The first two overloads do the magic for checking
76  // if the requirements of a concept are satisfied.
77  // The rest is just for checking base concepts in case
78  // of refinement.
79 
80  // This overload is present if type substitution for
81  // C::require(T...) is successful, i.e., if the T...
82  // matches the requirement of C. In this case this
83  // overload is selected because PriorityTag<1>
84  // is a better match for PrioriryTag<42> than
85  // PriorityTag<0> in the default overload.
86  template<class C, class... T,
87  decltype(std::declval<C>().require(std::declval<T>()...), 0) =0>
88  constexpr std::true_type matchesRequirement(PriorityTag<1>)
89  { return {}; }
90 
91  // If the above overload is ruled out by SFINAE because
92  // the T... does not match the requirements of C, then
93  // this default overload drops in.
94  template<class C, class... T>
95  constexpr std::false_type matchesRequirement(PriorityTag<0>)
96  { return {}; }
97 
98 
99 
100  // An empty list C of concepts is always matched by T...
101  template<class...T>
102  constexpr bool modelsConceptList(TypeList<>)
103  { return true; }
104 
105  // A nonempty list C0,..,CN of concepts is modeled
106  // by T... if it models the concept C0
107  // and all concepts in the list C1,..,CN.
108  template<class...T, class C0, class... CC>
109  constexpr bool modelsConceptList(TypeList<C0, CC...>)
110  { return models<C0, T...>() and modelsConceptList<T...>(TypeList<CC...>()); }
111 
112 
113 
114  // If C is an unrefined concept, then T... models C
115  // if it matches the requirement of C.
116  template<class C, class... T>
117  constexpr bool modelsConcept(PriorityTag<0>)
118  { return matchesRequirement<C, T...>(PriorityTag<42>()); }
119 
120  // If C is a refined concept, then T... models C
121  // if it matches the requirement of C and of
122  // all base concepts.
123  //
124  // This overload is used if C::BaseConceptList exists
125  // due to its higher priority.
126  template<class C, class... T,
127  decltype(typename C::BaseConceptList(), 0) = 0>
128  constexpr bool modelsConcept(PriorityTag<1>)
129  { return matchesRequirement<C, T...>(PriorityTag<42>()) and modelsConceptList<T...>(typename C::BaseConceptList()); }
130 
131  // This is the full concept check. It's defined here in the
132  // implementation namespace with 'constexpr bool' return type
133  // because we need a forward declaration in order to use it
134  // internally above.
135  //
136  // The actual interface function can then call this one and
137  // return the result as std::integral_constant<bool,*> which
138  // does not allow for a forward declaration because the return
139  // type is deduced.
140  template<class C, class... T>
141  constexpr bool models()
142  {
143  return modelsConcept<C, T...>(PriorityTag<42>());
144  }
145 
146 } // namespace Dune::Concept::Impl
147 
148 #endif // DOXYGEN
149 
150 } // namespace Dune::Concept
151 
152 
153 
183 template<class C, class... T>
184 constexpr auto models()
185 {
186  return Std::bool_constant<Concept::Impl::models<C, T...>()>();
187 }
188 
189 
190 
191 namespace Concept {
192 
193 #ifndef DOXYGEN
194 
195 namespace Impl {
196 
197  // #############################################################################
198  // # All functions following here are implementation details for the
199  // # for the tupleEntriesModel() function below.
200  // #############################################################################
201 
202  template<class C, class Tuple>
203  struct TupleEntriesModelHelper
204  {
205  template<class Accumulated, class T>
206  struct AccumulateFunctor
207  {
208  using type = typename std::integral_constant<bool, Accumulated::value and models<C, T>()>;
209  };
211  };
212 
213 } // namespace Dune::Concept::Impl
214 
215 #endif // DOXYGEN
216 
217 
218 // #############################################################################
219 // # The method tupleEntriesModel() does the actual check if the types in a tuple
220 // # model a concept using the implementation details above.
221 // #############################################################################
222 
223 template<class C, class Tuple>
224 constexpr auto tupleEntriesModel()
225  -> typename Impl::TupleEntriesModelHelper<C, Tuple>::Result
226 {
227  return {};
228 }
229 
230 // #############################################################################
231 // # The following require*() functions are just helpers that allow to
232 // # propagate a failed check as substitution failure. This is useful
233 // # inside of a concept definition.
234 // #############################################################################
235 
236 // Helper function for use in concept definitions.
237 // If the passed value b is not true, the concept will to be satisfied.
238 template<bool b, typename std::enable_if<b, int>::type = 0>
239 constexpr bool requireTrue()
240 {
241  return true;
242 }
243 
244 // Helper function for use in concept definitions.
245 template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
246 constexpr bool requireConcept()
247 {
248  return true;
249 }
250 
251 // Helper function for use in concept definitions.
252 // This allows to avoid using decltype
253 template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
254 constexpr bool requireConcept(T&&... /*t*/)
255 {
256  return true;
257 }
258 
259 // Helper function for use in concept definitions.
260 // This checks if the concept given as first type is modelled by all types in the tuple passed as argument
261 template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
262 constexpr bool requireConceptForTupleEntries()
263 {
264  return true;
265 }
266 
267 // Helper function for use in concept definitions.
268 // If the first passed type is not convertible to the second, the concept will not be satisfied.
269 template<class From, class To,
270  typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
271 constexpr bool requireConvertible()
272 {
273  return true;
274 }
275 
276 // Helper function for use in concept definitions.
277 // If passed argument is not convertible to the first passed type, the concept will not be satisfied.
278 template<class To, class From,
279  typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
280 constexpr bool requireConvertible(const From&)
281 {
282  return true;
283 }
284 
285 // Helper function for use in concept definitions.
286 // This will always evaluate to true. If just allow
287 // to turn a type into an expression. The failure happens
288 // already during substitution for the type argument.
289 template<typename T>
290 constexpr bool requireType()
291 {
292  return true;
293 }
294 
295 // Helper function for use in concept definitions.
296 // If first passed type is not a base class of second type, the concept will not be satisfied.
297 template<class Base, class Derived,
298  typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
299 constexpr bool requireBaseOf()
300 {
301  return true;
302 }
303 
304 // Helper function for use in concept definitions.
305 // If first passed type is not a base class of first arguments type, the concept will not be satisfied.
306 template<class Base, class Derived,
307  typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
308 constexpr bool requireBaseOf(const Derived&)
309 {
310  return true;
311 }
312 
313 // Helper function for use in concept definitions.
314 // If the passed types are not the same, the concept will not be satisfied.
315 template<class A, class B,
316  typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
317 constexpr bool requireSameType()
318 {
319  return true;
320 }
321 
322 
323 
324 } // namespace Dune::Concept
325 
326 } // namespace Dune
327 
328 
329 
330 
331 #endif // DUNE_COMMON_CONCEPT_HH
constexpr auto models()
Check if concept is modeled by given types.
Definition: concept.hh:184
F< Accumulated, Value >::type type
Result of the reduce operation.
Definition: tupleutility.hh:522
std::tuple< MetaType< T >... > TypeList
A simple type list.
Definition: typelist.hh:87
Dune namespace.
Definition: alignedallocator.hh:13
Base class for refined concepts.
Definition: concept.hh:54
Helper class for tagging priorities.
Definition: typeutilities.hh:73
Contains utility classes which can be used with std::tuple.
Utilities for type computations, constraining overloads, ...
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 1, 22:29, 2024)