Dune Core Modules (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#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// #############################################################################
194// # The method tupleEntriesModel() does the actual check if the types in a tuple
195// # model a concept using the implementation details above.
196// #############################################################################
197
198template<class C, class Tuple>
199constexpr auto tupleEntriesModel()
200{
201 return Dune::unpackIntegerSequence([&](auto... i) {
202 return std::conjunction<decltype(Dune::models<C, std::tuple_element_t<decltype(i)::value, Tuple>>())...>();
203 }, std::make_index_sequence<std::tuple_size_v<Tuple>>());
204}
205
206// #############################################################################
207// # The following require*() functions are just helpers that allow to
208// # propagate a failed check as substitution failure. This is useful
209// # inside of a concept definition.
210// #############################################################################
211
212// Helper function for use in concept definitions.
213// If the passed value b is not true, the concept will to be satisfied.
214template<bool b, typename std::enable_if<b, int>::type = 0>
215constexpr bool requireTrue()
216{
217 return true;
218}
219
220// Helper function for use in concept definitions.
221template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
222constexpr bool requireConcept()
223{
224 return true;
225}
226
227// Helper function for use in concept definitions.
228// This allows to avoid using decltype
229template<class C, class... T, typename std::enable_if<models<C, T...>(), int>::type = 0>
230constexpr bool requireConcept(T&&... /*t*/)
231{
232 return true;
233}
234
235// Helper function for use in concept definitions.
236// This checks if the concept given as first type is modelled by all types in the tuple passed as argument
237template<class C, class Tuple, typename std::enable_if<tupleEntriesModel<C, Tuple>(), int>::type = 0>
238constexpr bool requireConceptForTupleEntries()
239{
240 return true;
241}
242
243// Helper function for use in concept definitions.
244// If the first passed type is not convertible to the second, the concept will not be satisfied.
245template<class From, class To,
246 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
247constexpr bool requireConvertible()
248{
249 return true;
250}
251
252// Helper function for use in concept definitions.
253// If passed argument is not convertible to the first passed type, the concept will not be satisfied.
254template<class To, class From,
255 typename std::enable_if< std::is_convertible<From, To>::value, int>::type = 0>
256constexpr bool requireConvertible(const From&)
257{
258 return true;
259}
260
261// Helper function for use in concept definitions.
262// This will always evaluate to true. If just allow
263// to turn a type into an expression. The failure happens
264// already during substitution for the type argument.
265template<typename T>
266constexpr bool requireType()
267{
268 return true;
269}
270
271// Helper function for use in concept definitions.
272// If first passed type is not a base class of second type, the concept will not be satisfied.
273template<class Base, class Derived,
274 typename std::enable_if< std::is_base_of<Base, Derived>::value, int>::type = 0>
275constexpr bool requireBaseOf()
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 first arguments 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(const Derived&)
285{
286 return true;
287}
288
289// Helper function for use in concept definitions.
290// If the passed types are not the same, the concept will not be satisfied.
291template<class A, class B,
292 typename std::enable_if< std::is_same<A, B>::value, int>::type = 0>
293constexpr bool requireSameType()
294{
295 return true;
296}
297
298
299
300} // namespace Dune::Concept
301
302} // namespace Dune
303
304
305
306
307#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:184
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
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)