DUNE PDELab (2.7)

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
21namespace Dune {
22
32namespace Concept {
33
34
35
50template<class... BaseConcepts>
51struct Refines
52{
53 typedef TypeList<BaseConcepts...> BaseConceptList;
54};
55
56
57#ifndef DOXYGEN
58
59namespace 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
181template<class C, class... T>
182constexpr auto models()
183{
184 return Std::bool_constant<Concept::Impl::models<C, T...>()>();
185}
186
187
188
189namespace Concept {
190
191#ifndef DOXYGEN
192
193namespace 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
221template<class C, class Tuple>
222constexpr 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.
236template<bool b, typename std::enable_if<b, int>::type = 0>
237constexpr bool requireTrue()
238{
239 return true;
240}
241
242// Helper function for use in concept definitions.
243template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
244constexpr bool requireConcept()
245{
246 return true;
247}
248
249// Helper function for use in concept definitions.
250// This allows to avoid using decltype
251template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
252constexpr 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
259template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
260constexpr 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.
267template<class From, class To,
268 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
269constexpr 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.
276template<class To, class From,
277 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
278constexpr 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.
287template<typename T>
288constexpr 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.
295template<class Base, class Derived,
296 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
297constexpr 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.
304template<class Base, class Derived,
305 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
306constexpr 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.
313template<class A, class B,
314 typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
315constexpr 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.111.3 (Jul 15, 22:36, 2024)