DUNE PDELab (git)

treepath.hh
1// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=8 sw=2 sts=2:
3// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-GPL-2.0-only-with-PDELab-exception
5
6#ifndef DUNE_TYPETREE_TREEPATH_HH
7#define DUNE_TYPETREE_TREEPATH_HH
8
9#include <cstddef>
10#include <cassert>
11#include <iostream>
12#include <type_traits>
13
17#include <dune/common/indices.hh>
18#include <dune/common/hybridutilities.hh>
19#include <dune/common/typelist.hh>
20
21#include <dune/typetree/fixedcapacitystack.hh>
22#include <dune/typetree/utility.hh>
23
24namespace Dune {
25 namespace TypeTree {
26
27 // The Impl namespace collects some free standing functions helper functions
28 namespace Impl {
29 template<typename T>
30 struct check_size_t_impl
31 {
32 static constexpr auto check() {
33 return std::is_same_v<T, std::size_t>;
34 }
35 };
36
37 template<class T, T v>
38 struct check_size_t_impl<std::integral_constant<T,v>>
39 {
40 static constexpr auto check() {
41 return std::is_same_v<T, std::size_t>;
42 }
43 };
44
45 template<typename T>
46 constexpr auto check_size_t() {
47 return check_size_t_impl<T>::check();
48 }
49
50 template<typename T>
51 constexpr auto cast_size_t(const T & v) {
52 // check that T is an integral type that can be cast to std::size_t
53 static_assert(
54 std::is_convertible_v<T,std::size_t> &&
55 std::is_integral_v<T>,
56 "HybridTreePath indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
57 // positivity can only be checked at run-time
58 assert(v >= 0 &&
59 "HybridTreePath indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
60 return std::size_t(v);
61 }
62
63 template<class T, T v>
64 constexpr auto cast_size_t(std::integral_constant<T,v>) {
65 // check that T is an intergal type that can be cast to std::size_t
66 // and that v is positive
67 static_assert(
68 std::is_convertible_v<T,std::size_t> &&
69 std::is_integral_v<T> &&
70 v >= 0,
71 "HybridTreePath indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
72 return std::integral_constant<std::size_t,v>();
73 }
74
75 // these are helper functions that help triggering a deprecation warning
76 template<typename T>
77 [[deprecated("HybridTreePath index storage should be std::size_t or std::integral_constant<std::size_t,v>!\n"
78 "Using anything else is deprecated and will not possible after the 2.10 release.\n"
79 "It is adviced not to specify the template parameters expicitly,\n"
80 "but to use the helper functions `hybridTreePath` or `treePath`."
81 "These take care of converting indices to the appropriate storage.")]]
82 constexpr bool check_storage_type(MetaType<T>) {
83 return false;
84 }
85
86 // specialization of valid index type
87 template<std::size_t v>
88 constexpr bool check_storage_type(MetaType<std::integral_constant<std::size_t,v>>) {
89 return true;
90 }
91
92 // specialization of valid index type
93 constexpr bool check_storage_type(MetaType<std::size_t>) {
94 return true;
95 }
96 }
97
98 template<typename... T>
99 class HybridTreePath;
100
104
105 namespace TreePathType {
106 enum Type { fullyStatic, dynamic };
107 }
108
109 template<typename>
110 struct TreePathSize;
111
112 template<typename,std::size_t>
113 struct TreePathPushBack;
114
115 template<typename,std::size_t>
116 struct TreePathPushFront;
117
118 template<typename>
119 struct TreePathBack;
120
121 template<typename>
122 struct TreePathFront;
123
124 template<typename, std::size_t...>
125 struct TreePathPopBack;
126
127 template<typename>
128 struct TreePathPopFront;
129
130 template<typename, typename>
131 struct TreePathConcat;
132
133 template<std::size_t... i>
134 void print_tree_path(std::ostream& os)
135 {}
136
137 template<std::size_t k, std::size_t... i>
138 void print_tree_path(std::ostream& os)
139 {
140 os << k << " ";
141 print_tree_path<i...>(os);
142 }
143
145
156 template<typename... T>
158 {
159
160 // enable check for dune-typetree 2.10 and above
161#if DUNE_VERSION_GTE(TYPETREE,2,10)
162 // make sure that all indices use std::size_t as the underlying number type
163 static_assert((... && Impl::check_size_t<T>()),
164 "HybridTreePath index storage must be std::size_t or std::integral_constant<std::size_t,v>");
165#endif
166
167 public:
168
170 using index_sequence = std::index_sequence_for<T...>;
171
173 constexpr HybridTreePath()
174 {
175 [[maybe_unused]] constexpr bool check =
176 (... && Impl::check_storage_type(MetaType<T>()) );
177 }
178
179 constexpr HybridTreePath(const HybridTreePath& tp) = default;
180 constexpr HybridTreePath(HybridTreePath&& tp) = default;
181
182 constexpr HybridTreePath& operator=(const HybridTreePath& tp) = default;
183 constexpr HybridTreePath& operator=(HybridTreePath&& tp) = default;
184
186 explicit constexpr HybridTreePath(std::tuple<T...> t)
187 : _data(t)
188 {
189 [[maybe_unused]] constexpr bool check =
190 (... && Impl::check_storage_type(MetaType<T>()) );
191 }
192
194 template<typename... U,
195 typename std::enable_if_t<(sizeof...(T) > 0 && sizeof...(U) == sizeof...(T)),bool> = true>
196 explicit constexpr HybridTreePath(U... t)
197 : _data(t...) // we assume that all arguments are convertible to the types T...
198 {
199 [[maybe_unused]] constexpr bool check =
200 (... && Impl::check_storage_type(MetaType<T>()) );
201 }
202
204 [[nodiscard]] constexpr static index_sequence enumerate()
205 {
206 return {};
207 }
208
210 [[nodiscard]] constexpr static std::size_t size()
211 {
212 return sizeof...(T);
213 }
214
216 [[nodiscard]] constexpr static std::size_t max_size()
217 {
218 return size();
219 }
220
222 template<std::size_t i,
223 std::enable_if_t<(sizeof...(T) > i),bool> = true>
224 [[nodiscard]] constexpr auto operator[](Dune::index_constant<i>) const
225 {
226 return std::get<i>(_data);
227 }
228
230 [[nodiscard]] constexpr std::size_t operator[](std::size_t pos) const
231 {
232 std::size_t entry = 0;
233 Dune::Hybrid::forEach(enumerate(), [&] (auto i) {
234 if (i==pos)
235 entry = this->element(i);
236 });
237 return entry;
238 }
239
241 template<std::size_t i,
242 std::enable_if_t<(sizeof...(T) > i),bool> = true>
243 [[nodiscard]] constexpr auto element(Dune::index_constant<i> pos = {}) const
244 {
245 return std::get<i>(_data);
246 }
247
249 [[nodiscard]] constexpr std::size_t element(std::size_t pos) const
250 {
251 std::size_t entry = 0;
252 Dune::Hybrid::forEach(enumerate(), [&] (auto i) {
253 if (i==pos)
254 entry = this->element(i);
255 });
256 return entry;
257 }
258
260 template<std::size_t n = sizeof...(T),
261 std::enable_if_t<(n > 0 && n == sizeof...(T)),bool> = true>
262 [[nodiscard]] constexpr auto front() const
263 {
264 return std::get<0>(_data);
265 }
266
268 template<std::size_t n = sizeof...(T),
269 std::enable_if_t<(n > 0 && n == sizeof...(T)),bool> = true>
270 [[nodiscard]] constexpr auto back() const
271 {
272 return std::get<n-1>(_data);
273 }
274
275#ifndef DOXYGEN
276
277 // I can't be bothered to make all the external accessors friends of HybridTreePath,
278 // so we'll only hide the data tuple from the user in Doxygen.
279
280 using Data = std::tuple<T...>;
281 Data _data;
282
283#endif // DOXYGEN
284
285 };
286
288
294 template<typename... T>
295 [[nodiscard]] constexpr auto makeTreePath(const T... t)
296 {
297 // check that all entries are based on std::size_t
298 static_assert((... && Impl::check_size_t<T>()),
299 "HybridTreePath indices must be of type std::size_t or std::integral_constant<std::size_t,v>");
300 return HybridTreePath<T...>(t...);
301 }
302
304
311 template<typename... T>
312 [[nodiscard]] constexpr auto hybridTreePath(const T&... t)
313 {
314 return makeTreePath(Impl::cast_size_t(t)...);
315 }
316
318
325 template<typename... T>
326 [[nodiscard]] constexpr auto treePath(const T&... t)
327 {
328 return makeTreePath(Impl::cast_size_t(t)...);
329 }
330
331
333 template<typename... T>
334 [[nodiscard]] constexpr std::size_t treePathSize(const HybridTreePath<T...>&)
335 {
336 return sizeof...(T);
337 }
338
340
356 template<std::size_t i, typename... T>
357 [[nodiscard]] constexpr auto treePathEntry(const HybridTreePath<T...>& tp, index_constant<i> = {})
358 -> typename std::decay<decltype(std::get<i>(tp._data))>::type
359 {
360 return std::get<i>(tp._data);
361 }
362
364
379 template<std::size_t i,typename... T>
380 [[nodiscard]] constexpr std::size_t treePathIndex(const HybridTreePath<T...>& tp, index_constant<i> = {})
381 {
382 return std::get<i>(tp._data);
383 }
384
386
391 template<typename... T>
392 [[nodiscard]] constexpr auto back(const HybridTreePath<T...>& tp)
393 -> decltype(tp.back())
394 {
395 return tp.back();
396 }
397
399
404 template<typename... T>
405 [[nodiscard]] constexpr auto front(const HybridTreePath<T...>& tp)
406 -> decltype(tp.front())
407 {
408 return tp.front();
409 }
410
412
415 template<typename... T>
416 [[nodiscard]] constexpr HybridTreePath<T...,std::size_t> push_back(const HybridTreePath<T...>& tp, std::size_t i)
417 {
418 return HybridTreePath<T...,std::size_t>(std::tuple_cat(tp._data,std::make_tuple(i)));
419 }
420
422
436 template<std::size_t i, typename... T>
437 [[nodiscard]] constexpr HybridTreePath<T...,index_constant<i>> push_back(const HybridTreePath<T...>& tp, index_constant<i> i_ = {})
438 {
439 return HybridTreePath<T...,index_constant<i> >(std::tuple_cat(tp._data,std::make_tuple(i_)));
440 }
441
443
446 template<typename... T>
447 [[nodiscard]] constexpr HybridTreePath<std::size_t,T...> push_front(const HybridTreePath<T...>& tp, std::size_t element)
448 {
449 return HybridTreePath<std::size_t,T...>(std::tuple_cat(std::make_tuple(element),tp._data));
450 }
451
453
467 template<std::size_t i, typename... T>
468 [[nodiscard]] constexpr HybridTreePath<index_constant<i>,T...> push_front(const HybridTreePath<T...>& tp, index_constant<i> _i = {})
469 {
470 return HybridTreePath<index_constant<i>,T...>(std::tuple_cat(std::make_tuple(_i),tp._data));
471 }
472
474
485 template<typename I, typename... T, std::enable_if_t<(sizeof...(T) > 0),bool> = true>
486 [[nodiscard]] constexpr auto accumulate_back(const HybridTreePath<T...>& tp, I i) {
488 return push_back(pop_back(tp), plus(back(tp), i));
489 }
490
491
493
504 template<typename I, typename... T, std::enable_if_t<(sizeof...(T) > 0),bool> = true>
505 [[nodiscard]] constexpr auto accumulate_front(const HybridTreePath<T...>& tp, I i) {
507 return push_front(pop_front(tp), plus(front(tp), i));
508 }
509
511 template<class... Head, class... Other>
512 [[nodiscard]] constexpr auto join(const HybridTreePath<Head...>& head, const Other&... tail) {
513 return TypeTree::HybridTreePath{std::tuple_cat(head._data, tail._data...)};
514 }
515
517 template<class... T>
518 [[nodiscard]] constexpr auto reverse(const HybridTreePath<T...>& tp) {
519 constexpr std::size_t size = sizeof...(T);
520 return unpackIntegerSequence([&](auto... i){
521 return treePath(tp[index_constant<size-i-1>{}] ...);
522 }, std::make_index_sequence<size>{});
523 }
524
526
529 template <class... T, std::enable_if_t<(sizeof...(T) > 0),bool> = true>
530 [[nodiscard]] constexpr auto pop_front(const HybridTreePath<T...>& tp)
531 {
532 return unpackIntegerSequence([&](auto... i){
533 return HybridTreePath{std::make_tuple(std::get<i+1>(tp._data)...)};
534 }, std::make_index_sequence<(sizeof...(T) - 1)>{});
535 }
536
538
541 template <class... T, std::enable_if_t<(sizeof...(T) > 0),bool> = true>
542 [[nodiscard]] constexpr auto pop_back(const HybridTreePath<T...>& tp)
543 {
544 return unpackIntegerSequence([&](auto... i){
545 return HybridTreePath{std::make_tuple(std::get<i>(tp._data)...)};
546 }, std::make_index_sequence<(sizeof...(T) - 1)>{});
547 }
548
550
558 template <class... S, class... T>
559 [[nodiscard]] constexpr bool operator==(
560 const HybridTreePath<S...>& lhs,
561 const HybridTreePath<T...>& rhs)
562 {
563 if constexpr (sizeof...(S) == sizeof...(T)) {
564 if constexpr ((Dune::IsInteroperable<S,T>::value &&...)) {
565 return unpackIntegerSequence([&](auto... i){
566 return ((std::get<i>(lhs._data) == std::get<i>(rhs._data)) &&...);
567 }, std::make_index_sequence<(sizeof...(S))>{});
568 } else {
569 return false;
570 }
571 } else {
572 return false;
573 }
574 }
575
577
582 template <class S, S... lhs, class T, T... rhs>
583 [[nodiscard]] constexpr auto operator==(
584 const HybridTreePath<std::integral_constant<S,lhs>...>&,
585 const HybridTreePath<std::integral_constant<T,rhs>...>&)
586 {
587 return std::bool_constant<hybridTreePath(lhs...) == hybridTreePath(rhs...)>{};
588 }
589
590
592 template <class... S, class... T>
593 [[nodiscard]] constexpr auto operator!=(
594 const HybridTreePath<S...>& lhs,
595 const HybridTreePath<T...>& rhs)
596 {
597 return !(lhs == rhs);
598 }
599
601 template <class S, S... lhs, class T, T... rhs>
602 [[nodiscard]] constexpr auto operator!=(
603 const HybridTreePath<std::integral_constant<S,lhs>...>&,
604 const HybridTreePath<std::integral_constant<T,rhs>...>&)
605 {
606 return std::bool_constant<hybridTreePath(lhs...) != hybridTreePath(rhs...)>{};
607 }
608
609
610 inline namespace Literals {
611
613
617 template <char... digits>
618 constexpr auto operator"" _tp()
619 {
620 using namespace Dune::Indices::Literals;
621 return hybridTreePath(operator""_ic<digits...>());
622 }
623
624 } // end namespace Literals
625
626
627 template<std::size_t... i>
628 struct TreePathSize<HybridTreePath<index_constant<i>...> >
629 : public index_constant<sizeof...(i)>
630 {};
631
632
633 template<std::size_t k, std::size_t... i>
634 struct TreePathPushBack<HybridTreePath<index_constant<i>...>,k>
635 {
636 typedef HybridTreePath<index_constant<i>...,index_constant<k>> type;
637 };
638
639 template<std::size_t k, std::size_t... i>
640 struct TreePathPushFront<HybridTreePath<index_constant<i>...>,k>
641 {
642 typedef HybridTreePath<index_constant<k>,index_constant<i>...> type;
643 };
644
645 template<std::size_t k>
646 struct TreePathBack<HybridTreePath<index_constant<k>>>
647 : public index_constant<k>
648 {};
649
650 template<std::size_t j, std::size_t k, std::size_t... l>
651 struct TreePathBack<HybridTreePath<index_constant<j>,index_constant<k>,index_constant<l>...>>
652 : public TreePathBack<HybridTreePath<index_constant<k>,index_constant<l>...>>
653 {};
654
655 template<std::size_t k, std::size_t... i>
656 struct TreePathFront<HybridTreePath<index_constant<k>,index_constant<i>...>>
657 : public index_constant<k>
658 {};
659
660 template<std::size_t k, std::size_t... i>
661 struct TreePathPopBack<HybridTreePath<index_constant<k>>,i...>
662 {
663 typedef HybridTreePath<index_constant<i>...> type;
664 };
665
666 template<std::size_t j,
667 std::size_t k,
668 std::size_t... l,
669 std::size_t... i>
670 struct TreePathPopBack<HybridTreePath<index_constant<j>,index_constant<k>,index_constant<l>...>,i...>
671 : public TreePathPopBack<HybridTreePath<index_constant<k>,index_constant<l>...>,i...,j>
672 {};
673
674 template<std::size_t k, std::size_t... i>
675 struct TreePathPopFront<HybridTreePath<index_constant<k>,index_constant<i>...> >
676 {
677 typedef HybridTreePath<index_constant<i>...> type;
678 };
679
680 template<std::size_t... i, std::size_t... k>
681 struct TreePathConcat<HybridTreePath<index_constant<i>...>,HybridTreePath<index_constant<k>...> >
682 {
683 typedef HybridTreePath<index_constant<i>...,index_constant<k>...> type;
684 };
685
686#ifndef DOXYGEN
687
688 namespace impl {
689
690 // end of recursion
691 template<std::size_t i, typename... T>
692 typename std::enable_if<
693 (i == sizeof...(T))
694 >::type
695 print_hybrid_tree_path(std::ostream& os, const HybridTreePath<T...>& tp, index_constant<i> _i)
696 {}
697
698 // print current entry and recurse
699 template<std::size_t i, typename... T>
700 typename std::enable_if<
701 (i < sizeof...(T))
702 >::type
703 print_hybrid_tree_path(std::ostream& os, const HybridTreePath<T...>& tp, index_constant<i> _i)
704 {
705 os << treePathIndex(tp,_i) << " ";
706 print_hybrid_tree_path(os,tp,index_constant<i+1>{});
707 }
708
709 } // namespace impl
710
711#endif // DOXYGEN
712
714 template<typename... T>
715 std::ostream& operator<<(std::ostream& os, const HybridTreePath<T...>& tp)
716 {
717 os << "HybridTreePath< ";
718 impl::print_hybrid_tree_path(os, tp, index_constant<0>{});
719 os << ">";
720 return os;
721 }
722
723 template<std::size_t... i>
724 using StaticTreePath = HybridTreePath<Dune::index_constant<i>...>;
725
727
728 } // namespace TypeTree
729} //namespace Dune
730
731#endif // DUNE_TYPETREE_TREEPATH_HH
A hybrid version of TreePath that supports both compile time and run time indices.
Definition: treepath.hh:158
constexpr auto back() const
Get the last index value. Only available in non-empty paths.
Definition: treepath.hh:270
constexpr std::size_t element(std::size_t pos) const
Get the index value at position pos.
Definition: treepath.hh:249
constexpr HybridTreePath(std::tuple< T... > t)
Constructor from a std::tuple
Definition: treepath.hh:186
constexpr HybridTreePath(U... t)
Constructor from arguments.
Definition: treepath.hh:196
constexpr HybridTreePath()
Default constructor.
Definition: treepath.hh:173
constexpr auto element(Dune::index_constant< i > pos={}) const
Get the last index value.
Definition: treepath.hh:243
static constexpr std::size_t size()
Get the size (length) of this path.
Definition: treepath.hh:210
constexpr auto operator[](Dune::index_constant< i >) const
Get the index value at position pos.
Definition: treepath.hh:224
constexpr auto front() const
Get the first index value. Only available in non-empty paths.
Definition: treepath.hh:262
static constexpr index_sequence enumerate()
Returns an index_sequence for enumerating the components of this HybridTreePath.
Definition: treepath.hh:204
constexpr std::size_t operator[](std::size_t pos) const
Get the index value at position pos.
Definition: treepath.hh:230
static constexpr std::size_t max_size()
Get the size (length) of this path.
Definition: treepath.hh:216
std::index_sequence_for< T... > index_sequence
An index_sequence for the entries in this HybridTreePath.
Definition: treepath.hh:170
Documentation related stuff.
Traits for type conversions and type information.
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
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:256
constexpr auto plus
Function object for performing addition.
Definition: hybridutilities.hh:528
EnableIfInterOperable< T1, T2, bool >::type operator==(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for equality.
Definition: iteratorfacades.hh:238
EnableIfInterOperable< T1, T2, bool >::type operator!=(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for inequality.
Definition: iteratorfacades.hh:260
constexpr std::size_t treePathSize(const HybridTreePath< T... > &)
Returns the size (number of components) of the given HybridTreePath.
Definition: treepath.hh:334
constexpr auto accumulate_front(const HybridTreePath< T... > &tp, I i)
Hybrid utility that accumulates to the front of a multi-index.
Definition: treepath.hh:505
constexpr auto pop_front(const HybridTreePath< T... > &tp)
Removes first index on a HybridTreePath.
Definition: treepath.hh:530
constexpr auto reverse(const HybridTreePath< T... > &tp)
Reverses the order of the elements in the path.
Definition: treepath.hh:518
constexpr auto accumulate_back(const HybridTreePath< T... > &tp, I i)
Hybrid utility that accumulates to the back of a multi-index.
Definition: treepath.hh:486
constexpr auto join(const HybridTreePath< Head... > &head, const Other &... tail)
Join two tree paths into one.
Definition: treepath.hh:512
constexpr auto treePathEntry(const HybridTreePath< T... > &tp, index_constant< i >={}) -> typename std::decay< decltype(std::get< i >(tp._data))>::type
Returns a copy of the i-th element of the HybridTreePath.
Definition: treepath.hh:357
constexpr auto pop_back(const HybridTreePath< T... > &tp)
Removes last index on a HybridTreePath.
Definition: treepath.hh:542
constexpr auto hybridTreePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:312
constexpr std::size_t treePathIndex(const HybridTreePath< T... > &tp, index_constant< i >={})
Returns the index value of the i-th element of the HybridTreePath.
Definition: treepath.hh:380
constexpr auto makeTreePath(const T... t)
helper function to construct a new HybridTreePath from the given indices.
Definition: treepath.hh:295
constexpr auto treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:326
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integer_sequence< T, II..., T(IN)> push_back(std::integer_sequence< T, II... >, std::integral_constant< T, IN >={})
Append an index IN to the back of the sequence.
Definition: integersequence.hh:69
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
constexpr std::integer_sequence< T, T(I0), II... > push_front(std::integer_sequence< T, II... >, std::integral_constant< T, I0 >={})
Append an index I0 to the front of the sequence.
Definition: integersequence.hh:64
constexpr std::integral_constant< T, I0 > front(std::integer_sequence< T, I0, II... >)
Return the first entry of the sequence.
Definition: integersequence.hh:39
constexpr std::integer_sequence< T, II... > tail(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the tail sequence.
Definition: integersequence.hh:58
constexpr auto back(std::integer_sequence< T, II... > seq)
Return the last entry of the sequence.
Definition: integersequence.hh:44
constexpr std::integral_constant< T, I0 > head(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the single head element.
Definition: integersequence.hh:53
STL namespace.
Checks whether two types are interoperable.
Definition: typetraits.hh:65
A type that refers to another type.
Definition: typelist.hh:33
Various macros to work with Dune module version numbers.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)