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