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
19namespace Dune {
20
30namespace Concept {
31
32
33
48template<class... BaseConcepts>
49struct Refines
50{
51 typedef TypeList<BaseConcepts...> BaseConceptList;
52};
53
54
55#ifndef DOXYGEN
56
57namespace 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
179template<class C, class... T>
180constexpr auto models()
181{
182 return Std::bool_constant<Concept::Impl::models<C, T...>()>();
183}
184
185
186
187namespace Concept {
188
189#ifndef DOXYGEN
190
191namespace 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
219template<class C, class Tuple>
220constexpr 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.
234template<bool b, typename std::enable_if<b, int>::type = 0>
235constexpr bool requireTrue()
236{
237 return true;
238}
239
240// Helper function for use in concept definitions.
241template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
242constexpr bool requireConcept()
243{
244 return true;
245}
246
247// Helper function for use in concept definitions.
248// This allows to avoid using decltype
249template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
250constexpr 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
257template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
258constexpr 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.
265template<class From, class To,
266 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
267constexpr 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.
274template<class To, class From,
275 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
276constexpr 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.
285template<typename T>
286constexpr 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.
293template<class Base, class Derived,
294 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
295constexpr 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.
302template<class Base, class Derived,
303 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
304constexpr 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.
311template<class A, class B,
312 typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
313constexpr 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.111.3 (Dec 26, 23:30, 2024)