1 // RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -fcxx-exceptions
3 template<typename T
> struct remove_reference
{ typedef T type
; };
4 template<typename T
> struct remove_reference
<T
&> { typedef T type
; };
5 template<typename T
> struct remove_reference
<T
&&> { typedef T type
; };
7 template<typename T
> constexpr T
&&forward(typename remove_reference
<T
>::type
&t
) noexcept
{ return static_cast<T
&&>(t
); }
8 template<typename T
> constexpr T
&&forward(typename remove_reference
<T
>::type
&&t
) noexcept
{ return static_cast<T
&&>(t
); }
9 template<typename T
> constexpr typename remove_reference
<T
>::type
&&move(T
&&t
) noexcept
{ return static_cast<typename remove_reference
<T
>::type
&&>(t
); }
11 template<typename T
> T
declval() noexcept
;
14 template<unsigned N
> struct select
{}; // : integral_constant<unsigned, N> {};
15 template<typename T
> struct type
{};
17 template<typename
...T
> union either_impl
;
19 template<> union either_impl
<> {
21 void destroy(...) { throw "logic_error"; }
24 template<typename T
, typename
...Ts
> union either_impl
<T
, Ts
...> {
27 either_impl
<Ts
...> rest
;
28 typedef either_impl
<Ts
...> rest_t
;
31 constexpr either_impl(select
<0>, T
&&t
) : val(move(t
)) {}
33 template<unsigned N
, typename U
>
34 constexpr either_impl(select
<N
>, U
&&u
) : rest(select
<N
-1>(), move(u
)) {}
36 constexpr static unsigned index(type
<T
>) { return 0; }
38 constexpr static unsigned index(type
<U
> t
) {
39 return decltype(rest
)::index(t
) + 1;
42 void destroy(unsigned elem
) {
44 rest
.destroy(elem
- 1);
49 constexpr const T
&get(select
<0>) { return val
; }
50 template<unsigned N
> constexpr const decltype(static_cast<const rest_t
&>(rest
).get(select
<N
-1>{})) get(select
<N
>) {
51 return rest
.get(select
<N
-1>{});
59 template<typename
...U
>
60 constexpr a(U
&&...u
) : value
{forward
<U
>(u
)...} {}
62 template<typename T
> using an
= a
<T
>;
64 template<typename T
, typename U
> T
throw_(const U
&u
) { throw u
; }
66 template<typename
...T
>
69 detail::either_impl
<T
...> impl
;
70 typedef decltype(impl
) impl_t
;
74 constexpr either(a
<U
> &&t
) :
75 elem(impl_t::index(detail::type
<U
>())),
76 impl(detail::select
<impl_t::index(detail::type
<U
>())>(), move(t
.value
)) {}
78 // Destruction disabled to allow use in a constant expression.
79 // FIXME: declare a destructor iff any element has a nontrivial destructor
80 //~either() { impl.destroy(elem); }
82 constexpr unsigned index() noexcept
{ return elem
; }
84 template<unsigned N
> using const_get_result
=
85 decltype(static_cast<const impl_t
&>(impl
).get(detail::select
<N
>{}));
88 constexpr const_get_result
<N
> get() {
89 // Can't just use throw here, since that makes the conditional a prvalue,
90 // which means we return a reference to a temporary.
91 return (elem
!= N
? throw_
<const_get_result
<N
>>("bad_either_get")
92 : impl
.get(detail::select
<N
>{}));
96 constexpr const U
&get() {
97 return get
<impl_t::index(detail::type
<U
>())>();
101 typedef either
<int, char, double> icd
;
102 constexpr icd icd1
= an
<int>(4);
103 constexpr icd icd2
= a
<char>('x');
104 constexpr icd icd3
= a
<double>(6.5);
106 static_assert(icd1
.get
<int>() == 4, "");
107 static_assert(icd2
.get
<char>() == 'x', "");
108 static_assert(icd3
.get
<double>() == 6.5, "");
111 constexpr non_triv() : n(5) {}
114 constexpr either
<const icd
*, non_triv
> icd4
= a
<const icd
*>(&icd2
);
115 constexpr either
<const icd
*, non_triv
> icd5
= a
<non_triv
>();
117 static_assert(icd4
.get
<const icd
*>()->get
<char>() == 'x', "");
118 static_assert(icd5
.get
<non_triv
>().n
== 5, "");