DUNE-FEM (unstable)

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