Dune Core Modules (2.7.0)

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