Dune Core Modules (2.9.0)

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