-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathtagged.tex
145 lines (131 loc) · 4.77 KB
/
tagged.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
%!TEX root = stl2-ts.tex
\infannex{tagged}{Reference implementation for \tcode{tagged}}
\pnum Below is a reference implementation of the \tcode{tagged} class template described in
\ref{taggedtup.tagged}, and also \tcode{tagged_pair}~(\ref{tagged.pairs}),
\tcode{tagged_tuple}~(\ref{tagged.tuple}), and \tcode{tag::in}~(\ref{alg.tagspec}).
\begin{codeblock}
namespace std { namespace experimental { namespace ranges { inline namespace v1 {
namespace tag { struct __specifier_tag { }; }
template <class T>
struct __tag_spec { };
template <class Spec, class Arg>
struct __tag_spec<Spec(Arg)> { using type = Spec; };
template <class T>
struct __tag_elem { };
template <class Spec, class Arg>
struct __tag_elem<Spec(Arg)> { using type = Arg; };
template <class T>
concept bool TagSpecifier() {
return DerivedFrom<T, tag::__specifier_tag>();
}
template <class T>
concept bool TaggedType() {
return requires {
typename __tag_spec<T>::type;
requires TagSpecifier<typename __tag_spec<T>::type>();
};
}
template <class Base, TagSpecifier... Tags>
requires sizeof...(Tags) >= tuple_size<Base>::value
struct tagged;
}}}
template <class Base, class... Tags>
struct tuple_size<experimental::ranges::tagged<Base, Tags...>>
: tuple_size<Base> { };
template <size_t N, class Base, class... Tags>
struct tuple_element<N, experimental::ranges::tagged<Base, Tags...>>
: tuple_element<N, Base> { };
namespace experimental { namespace ranges { inline namespace v1 {
struct __getters {
private:
template <class, TagSpecifier...>
requires sizeof...(Tags) >= tuple_size<Base>::value
friend struct tagged;
template <class Type, class Indices, TagSpecifier... Tags>
struct collect_;
template <class Type, size_t... Is, TagSpecifier... Tags>
struct collect_<Type, index_sequence<Is...>, Tags...>
: Tags::template getter<Type, Is>... {
collect_() = default;
collect_(const collect_&) = default;
collect_& operator=(const collect_&) = default;
private:
template <class Base, TagSpecifier... Tags>
requires sizeof...(Tags) <= tuple_size<Base>::value
friend struct tagged;
~collect_() = default;
};
template <class Type, TagSpecifier... Tags>
using collect = collect_<Type, make_index_sequence<sizeof...(Tags)>, Tags...>;
};
template <class Base, TagSpecifier... Tags>
struct tagged
: Base, __getters::collect<tagged<Base, Tags...>, Tags...> {
using Base::Base;
tagged() = default;
tagged(tagged&&) = default;
tagged(const tagged&) = default;
tagged &operator=(tagged&&) = default;
tagged &operator=(const tagged&) = default;
template <typename Other>
requires Constructible<Base, Other>()
tagged(tagged<Other, Tags...> &&that)
: Base(static_cast<Other &&>(that)) { }
template <typename Other>
requires Constructible<Base, const Other&>()
tagged(const tagged<Other, Tags...> &that)
: Base(static_cast<const Other&>(that)) { }
template <typename Other>
requires Assignable<Base&, Other>()
tagged& operator=(tagged<Other, Tags...>&& that) {
static_cast<Base&>(*this) = static_cast<Other&&>(that);
return *this;
}
template <typename Other>
requires Assignable<Base&, const Other&>()
tagged& operator=(const tagged<Other, Tags...>& that) {
static_cast<Base&>(*this) = static_cast<const Other&>(that);
return *this;
}
template <class U>
requires Assignable<Base&, U>() && !Same<decay_t<U>, tagged>()
tagged& operator=(U&& u) {
static_cast<Base&>(*this) = std::forward<U>(u);
return *this;
}
};
template <TaggedType F, TaggedType S>
using tagged_pair =
tagged<pair<typename __tag_elem<F>::type, typename __tag_elem<S>::type>,
typename __tag_spec<F>::type, typename __tag_spec<S>::type>;
template <TaggedType... Types>
using tagged_tuple =
tagged<tuple<typename __tag_elem<Types>::type...>,
typename __tag_spec<Types>::type...>;
namespace tag {
struct in : __specifier_tag {
private:
friend __getters;
template <class Derived, size_t I>
struct getter {
getter() = default;
getter(const getter&) = default;
getter &operator=(const getter&) = default;
constexpr decltype(auto) in() & {
return get<I>(static_cast<Derived &>(*this));
}
constexpr decltype(auto) in() && {
return get<I>(static_cast<Derived &&>(*this));
}
constexpr decltype(auto) in() const & {
return get<I>(static_cast<const Derived &>(*this));
}
private:
friend __getters;
~getter() = default;
};
}
// Other tag specifiers defined similarly, see \ref{alg.tagspec}
}
}}}}
\end{codeblock}