Dune Core Modules (2.6.0)

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