// RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -fcxx-exceptions template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template constexpr T &&forward(typename remove_reference::type &t) noexcept { return static_cast(t); } template constexpr T &&forward(typename remove_reference::type &&t) noexcept { return static_cast(t); } template constexpr typename remove_reference::type &&move(T &&t) noexcept { return static_cast::type&&>(t); } template T declval() noexcept; namespace detail { template struct select {}; // : integral_constant {}; template struct type {}; template union either_impl; template<> union either_impl<> { void get(...); void destroy(...) { throw "logic_error"; } }; template union either_impl { private: T val; either_impl rest; typedef either_impl rest_t; public: constexpr either_impl(select<0>, T &&t) : val(move(t)) {} template constexpr either_impl(select, U &&u) : rest(select(), move(u)) {} constexpr static unsigned index(type) { return 0; } template constexpr static unsigned index(type t) { return decltype(rest)::index(t) + 1; } void destroy(unsigned elem) { if (elem) rest.destroy(elem - 1); else val.~T(); } constexpr const T &get(select<0>) { return val; } template constexpr const decltype(static_cast(rest).get(select{})) get(select) { return rest.get(select{}); } }; } template struct a { T value; template constexpr a(U &&...u) : value{forward(u)...} {} }; template using an = a; template T throw_(const U &u) { throw u; } template class either { unsigned elem; detail::either_impl impl; typedef decltype(impl) impl_t; public: template constexpr either(a &&t) : elem(impl_t::index(detail::type())), impl(detail::select())>(), move(t.value)) {} // Destruction disabled to allow use in a constant expression. // FIXME: declare a destructor iff any element has a nontrivial destructor //~either() { impl.destroy(elem); } constexpr unsigned index() noexcept { return elem; } template using const_get_result = decltype(static_cast(impl).get(detail::select{})); template constexpr const_get_result get() { // Can't just use throw here, since that makes the conditional a prvalue, // which means we return a reference to a temporary. return (elem != N ? throw_>("bad_either_get") : impl.get(detail::select{})); } template constexpr const U &get() { return get())>(); } }; typedef either icd; constexpr icd icd1 = an(4); constexpr icd icd2 = a('x'); constexpr icd icd3 = a(6.5); static_assert(icd1.get() == 4, ""); static_assert(icd2.get() == 'x', ""); static_assert(icd3.get() == 6.5, ""); struct non_triv { constexpr non_triv() : n(5) {} int n; }; constexpr either icd4 = a(&icd2); constexpr either icd5 = a(); static_assert(icd4.get()->get() == 'x', ""); static_assert(icd5.get().n == 5, "");