Dune Core Modules (2.5.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
15
16
17namespace Dune {
18
19
20
28namespace Concept {
29
30
31
44template<class... BaseConcepts>
45struct Refines
46{
47 typedef TypeList<BaseConcepts...> BaseConceptList;
48};
49
50
51
52namespace 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>
100 constexpr bool modelsConceptList(TypeList<C0, 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>
108 constexpr bool modelsConcept(PriorityTag<0>)
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>
119 constexpr bool modelsConcept(PriorityTag<1>)
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
171template<class C, class... T>
172constexpr auto models()
173{
174 return Std::bool_constant<Concept::Imp::models<C, T...>()>();
175}
176
177
178
179namespace Concept {
180
181namespace 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>
189 struct TupleEntriesModelHelper
190 {
191 template<class Accumulated, class T>
192 struct AccumulateFunctor
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
208template<class C, class Tuple>
209constexpr auto tupleEntriesModel()
210 -> typename Imp::TupleEntriesModelHelper<C, Tuple>::Result
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.
223template<bool b, typename std::enable_if<b, int>::type = 0>
224constexpr bool requireTrue()
225{
226 return true;
227}
228
229// Helper function for use in concept definitions.
230template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
231constexpr bool requireConcept()
232{
233 return true;
234}
235
236// Helper function for use in concept definitions.
237// This allows to avoid using decltype
238template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
239constexpr 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
246template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
247constexpr bool requireConceptForTupleEntries()
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.
254template<class From, class To,
255 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
256constexpr 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.
263template<class To, class From,
264 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
265constexpr 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.
274template<typename T>
275constexpr 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.
282template<class Base, class Derived,
283 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
284constexpr 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.
291template<class Base, class Derived,
292 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
293constexpr 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.
300template<class A, class B,
301 typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
302constexpr 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
F< Accumulated, Value >::type type
Result of the reduce operation.
Definition: tupleutility.hh:605
Dune namespace.
Definition: alignment.hh:11
constexpr auto models()
Check if concept is modeled by given types.
Definition: concept.hh:172
Base class for refined concepts.
Definition: concept.hh:46
Helper class for tagging priorities.
Definition: typeutilities.hh:60
A simple type list.
Definition: typelist.hh:31
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 (Jun 13, 22:32, 2024)