Skip to main content
Code Review

Return to Question

Notice removed Authoritative reference needed by Community Bot
Bounty Ended with no winning answer by Community Bot
30k symbols exceeded, so text reduced
Source Link

This implementation of discriminated union based on C++ inherent unions and inspired by this article and this articles.

As you can note there are at least two tradeoffs to spite of runtime performance: those places with _rhs.which() == which_ comparisons in a row (destruction, construction, conversion, assignment, conversion assignment) and ugly (due to pointers using) places ::new (&head_.value_) first(_rhs.head_.value_); where in-place construction performed. Placement new breaks constexpr requirements (as I know). There's nothing for it.

This implementation of discriminated union based on C++ inherent unions and inspired by this article.

As you can note there are at least two tradeoffs to spite of runtime performance: those places with _rhs.which() == which_ comparisons in a row (destruction, construction, conversion, assignment, conversion assignment) and ugly (due to pointers using) places ::new (&head_.value_) first(_rhs.head_.value_); where in-place construction performed. Placement new breaks constexpr requirements (as I know). There's nothing for it.

This implementation of discriminated union based on C++ inherent unions and inspired by this and this articles.

Notice added Authoritative reference needed by Tomilov Anatoliy
Bounty Started worth 50 reputation by Tomilov Anatoliy
added 96 characters in body
Source Link

Here the repository containing the last version.

Here the repository containing the last version.

added 218 characters in body
Source Link
#pragma once
#include <type_traits>
#include <limits>
#include <utility>
#include <cassert>
namespace versatile
{
namespace type_traits
{
template< typename from, typename to >
struct copy_ref
{
 using type = to;
};
template< typename from, typename to >
struct copy_ref< from &, to >
{
 using type = to &;
};
template< typename from, typename to >
struct copy_ref< from &&, to >
{
 using type = to &&;
};
template< typename from, typename to >
struct copy_cv
{
 using type = to;
};
template< typename from, typename to >
struct copy_cv< volatile from const, to >
{
 using type = volatile to const;
};
template< typename from, typename to >
struct copy_cv< from const, to >
{
 using type = to const;
};
template< typename from, typename to >
struct copy_cv< volatile from, to >
{
 using type = volatile to;
};
}
template< typename from, typename to >
using copy_ref = typename type_traits::copy_ref< from, to >::type;
template< typename from, typename to >
using copy_cv = typename type_traits::copy_cv< from, to >::type;
template< typename from, typename to >
using copy_refcv = copy_ref< from, copy_cv< std::remove_reference_t< from >, to > >;
template< typename type, typename ...arguments >
using result_of = decltype(std::declval< type >()(std::declval< arguments >()...));
static constexpr std::size_t npos = std::numeric_limits< std::size_t >::max();
template< std::size_t which = npos, typename type = void >
struct indexed
{
 std::size_t which_ = which;
 type value_;
 template< typename ...arguments >
 explicit
 constexpr
 indexed(arguments &&... _arguments)
 : value_(std::forward< arguments >(_arguments)...)
 { ; }
};
template<>
struct indexed< npos, void >
{
 std::size_t which_ = npos;
};
template< typename ...types >
union versatile;
template<>
union versatile<>
{
 static constexpr std::size_t which_ = npos;
private :
 using head = indexed<>;
 head head_{};
public :
 template< typename type = void >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 return npos;
 }
 template< std::size_t _which >
 using at = void;
 using this_type = void;
 constexpr
 std::size_t
 which() const noexcept
 {
 return npos;
 }
 template< typename type = void >
 constexpr
 bool
 is_active() const noexcept
 {
 return false;
 }
 constexpr
 versatile() noexcept = default;
 constexpr
 void
 swap(versatile &) noexcept
 {
 return;
 }
};
template< typename first, typename ...rest >
union versatile< first, rest... >
{
 static_assert(std::is_standard_layout< first >(), "!");
 static constexpr std::size_t which_ = sizeof...(rest);
private :
 using head = indexed< which_, first >;
 using tail = versatile< rest... >;
 head head_;
 tail tail_;
public :
 template< typename type = first >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 if (std::is_same< type, first >()) {
 return which_;
 } else {
 return tail::template index< type >();
 }
 }
 template< std::size_t _which >
 using at = std::conditional_t< (_which == which_), first, typename tail::template at< _which > >;
 using this_type = first;
 constexpr
 std::size_t
 which() const noexcept
 {
 return head_.which_;
 }
 template< typename type = first >
 constexpr
 bool
 is_active() const noexcept
 {
 if (std::is_same< type, first >()) {
 return (which() == which_);
 } else {
 return tail_.template is_active< type >();
 }
 }
 ~versatile() noexcept(std::is_nothrow_destructible< first >() && std::is_nothrow_destructible< tail >())
 {
 if (is_active()) {
 head_.~head();
 } else {
 tail_.~tail();
 }
 }
private :
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::true_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< first, arguments... >())
 : head_(std::forward< arguments >(_arguments)...)
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::false_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< tail, arguments... >())
 : tail_(std::forward< arguments >(_arguments)...)
 { ; }
public :
 constexpr
 versatile() noexcept(std::is_nothrow_constructible< versatile, typename std::is_default_constructible< first >::type >())
 : versatile(typename std::is_default_constructible< first >::type{})
 { ; }
 template< typename argument >
 constexpr
 versatile(argument && _argument) noexcept(std::is_nothrow_constructible< tail, argument >())
 : versatile(std::false_type{}, std::forward< argument >(_argument))
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(arguments &&... _arguments) noexcept(std::is_nothrow_constructible< versatile, typename std::is_constructible< first, arguments... >::type, arguments... >())
 : versatile(typename std::is_constructible< first, arguments... >::type{}, std::forward< arguments >(_arguments)...)
 { ; }
 versatile(versatile const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile const && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 versatile(versatile && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 constexpr
 versatile(first const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first const && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile(first && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile &
 operator = (versatile const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile const && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (versatile && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (first const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first const && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 constexpr
 versatile &
 operator = (first && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 template< typename rhs >
 constexpr
 versatile &
 operator = (rhs && _rhs) noexcept(std::is_nothrow_assignable< tail &, rhs >())
 {
 tail_ = std::forward< rhs >(_rhs);
 return *this;
 }
 constexpr
 void
 swap(versatile & _other) noexcept
 {
 assert(_other.which() == which());
 if (is_active()) {
 using std::swap;
 swap(_other.head_.value_, head_.value_);
 } else {
 tail_.swap( _other.tail_);
 }
 }
 explicit
 constexpr
 operator first const & () const & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type const & () const & noexcept
 {
 return static_cast< type const & >(tail_);
 }
 explicit
 constexpr
 operator first & () & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type & () & noexcept
 {
 return static_cast< type & >(tail_);
 }
 explicit
 constexpr
 operator first const && () const && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type const && () const && noexcept
 {
 return static_cast< type const && >(tail_);
 }
 explicit
 constexpr
 operator first && () && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type && () && noexcept
 {
 return static_cast< type && >(tail_);
 }
private :
 template< typename type, typename result_type, typename visitor, typename visitable, typename ...arguments >
 static
 constexpr
 result_type
 caller(visitor && _visitor, visitable && _visitable, arguments &&... _arguments)
 {
 // There is known clang++ bug #19917 for static_cast to rvalue reference. To avoid hard error here: replace "static_cast< type >(std::forward< visitable >(_visitable))" with "reinterpret_cast< type >(_visitable.head_.value_)".
 return std::forward< visitor >(_visitor)(static_cast< type >(std::forward< visitable >(_visitable)), std::forward< arguments >(_arguments)...);
 }
public :
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &, result_type, visitor, versatile const &, arguments... >, versatile::caller< rest const &, result_type, visitor, versatile const &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &, result_type, visitor, versatile &, arguments... >, versatile::caller< rest &, result_type, visitor, versatile &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &&, result_type, visitor, versatile const &&, arguments... >, versatile::caller< rest const &&, result_type, visitor, versatile const &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &&, result_type, visitor, versatile &&, arguments... >, versatile::caller< rest &&, result_type, visitor, versatile &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
};
template< typename ...types >
constexpr
void
swap(versatile< types... > & _lhs, versatile< types... > & _rhs) noexcept
{
 assert(_lhs.which() == _rhs.which());
 _lhs.swap(_rhs);
}
template< typename type >
struct is_versatile
 : std::false_type
{
};
template< typename ...types >
struct is_versatile< versatile< types... > >
 : std::true_type
{
};
template< typename versatile, typename type >
constexpr std::size_t index = versatile::template index< type >();
template< typename versatile, std::size_t index >
using at = typename versatile::template at< index >;
namespace visitation
{
template< typename type, bool = is_versatile< std::decay_t< type > >() >
struct underlying_type;
template< typename visitable >
struct underlying_type< visitable, true >
{
 using type = copy_refcv< visitable, typename std::decay_t< visitable >::this_type >;
};
template< typename general_type >
struct underlying_type< general_type, false >
{
 using type = general_type &&;
};
template< typename result_type, typename supervisitor, typename type, bool = is_versatile< std::decay_t< type > >() >
struct subvisitor;
template< typename result_type, typename supervisitor, typename visitable >
struct subvisitor< result_type, supervisitor, visitable, true >
{
 supervisitor && supervisitor_;
 visitable && visitable_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< visitable >(visitable_).apply_visitor(std::forward< supervisitor >(supervisitor_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename supervisitor, typename type >
struct subvisitor< result_type, supervisitor, type, false >
{
 supervisitor && supervisitor_;
 type && value_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< supervisitor >(supervisitor_)(std::forward< type >(value_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename ...visitables >
struct visitor_partially_applier;
template< typename result_type >
struct visitor_partially_applier< result_type >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor) const
 {
 return std::forward< visitor >(_visitor)();
 }
};
template< typename result_type, typename first, typename ...rest >
struct visitor_partially_applier< result_type, first, rest... >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor, first && _first, rest &&... _rest) const
 {
 subvisitor< result_type, visitor, first > subvisitor_{std::forward< visitor >(_visitor), std::forward< first >(_first)};
 return visitor_partially_applier< result_type, rest... >{}(subvisitor_, std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor, typename first, typename ...rest >
constexpr
decltype(auto)
apply_visitor(visitor && _visitor, first && _first, rest &&... _rest)
{
 using namespace visitation;
 using result_type = result_of< visitor, typename underlying_type< first >::type, typename underlying_type< rest >::type... >;
 return visitor_partially_applier< result_type, first, rest... >{}(std::forward< visitor >(_visitor), std::forward< first >(_first), std::forward< rest >(_rest)...);
}
namespace visitation
{
template< typename visitor >
struct delayed_visitor_applier
{
 visitor visitor_;
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor >
constexpr
visitation::delayed_visitor_applier< visitor >
apply_visitor(visitor && _visitor) noexcept
{
 return {std::forward< visitor >(_visitor)};
}
}
#include "versatile.hpp"
#include <string>
#include <array>
#include <utility>
#ifdef _DEBUG
#include <iostream>
#include <iomanip>
#endif
#include <cstdlib>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
namespace
{
struct introspector
{
 template< typename ...types >
 std::string
 operator () (types...) const
 {
 return __PRETTY_FUNCTION__;
 }
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
namespace
{
template< std::size_t I >
struct T
{
};
struct Pvisitor
{
 template< std::size_t ...I >
 std::array< std::size_t, sizeof...(I) >
 operator () (T< I > const &...) const
 {
 return {I...};
 }
};
template< typename L, typename ...R >
bool
lvaluelizer(L const & _lhs, R const &... _rhs) // To avoid known clang bug #19917 https://llvm.org/bugs/show_bug.cgi?id=19917 makes all parametres lvalues.
{
 using versatile::apply_visitor;
 return (_lhs == apply_visitor(visitor{}, _rhs...));
}
template< std::size_t ...M, std::size_t ...N >
bool
invoke(std::index_sequence< M... > const &, std::index_sequence< N... > const &)
{
 using versatile::apply_visitor;
 using versatile::versatile;
 return (apply_visitorlvaluelizer(P{}, versatile< T<std::array< Mstd::size_t, >sizeof...(N) >{T< (N % sizeof...(M)) >{}}...)}, ==versatile< std::array<T< std::size_t,M sizeof>...(N) >{T< (N % sizeof...(M)) >{}}...});
}
template< std::size_t M, std::size_t N = M >
bool
test()
{
 return invoke(std::make_index_sequence< M >{}, std::make_index_sequence< N >{});
}
}
#pragma clang diagnostic pop
int
main()
{
 using namespace versatile;
 {
 using V0 = versatile<>;
 assert(!V0{}.is_active());
 using V1 = versatile< V0 >;
 assert(V1{}.which() == 0);
 assert((index< V1, V0 > == 0));
 using V2 = versatile< V1, V0 >;
 assert(V2{}.which() == 1);
 assert((index< V2, V1 > == 1));
 using V3 = versatile< V2, V1, V0 >;
 assert(V3{}.which() == 2);
 assert((index< V3, V2 > == 2));
 using V4 = versatile< V3, V2, V1, V0 >;
 assert(V4{}.which() == 3);
 assert((index< V4, V3 > == 3));
 using V5 = versatile< V4, V3, V2, V1, V0 >;
 assert(V5{}.which() == 4);
 assert((index< V5, V4 > == 4));
 static_assert(std::is_same< V4, at< V5, 4 > >(), "!");
 }
 {
 struct empty {};
 using V = versatile< empty, int, float, double, long double >;
 assert(V{}.is_active());
 assert(V{}.which() == 4);
 assert(V{0}.which() == 3);
 assert(V{1.0f}.which() == 2);
 assert(V{2.0}.which() == 1);
 assert(V{3.0L}.which() == 0);
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-member-function"
 struct A { explicit A(int, int) {} };
#pragma clang diagnostic pop
 struct B { explicit B(int, double) {} };
 using V = versatile< B, A, int >;
 V v0{1};
 assert((v0.which() == index< V, int >));
 V v1{1, 2};
 assert((v1.which() == index< V, B >)); // !
 V v2{1, 2.0};
 assert((v2.which() == index< V, B >));
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunneeded-member-function"
 struct A { ~A() noexcept(true) {} };
 struct B { ~B() noexcept(false) {} };
#pragma clang diagnostic pop
 using VA = versatile< A >;
 using VB = versatile< B >;
 using VAB = versatile< A, B >;
 static_assert(std::is_nothrow_destructible< A >(), "!");
 static_assert(!std::is_nothrow_destructible< B >(), "!");
 static_assert(std::is_nothrow_destructible< VA >(), "!");
 static_assert(!std::is_nothrow_destructible< VB >(), "!");
 static_assert(!std::is_nothrow_destructible< VAB >(), "!");
 }
 {
 struct A { A() {} A & operator = (A const &) = default; A & operator = (A &) = delete; };
 using V = versatile< A >;
 V v;
 A const a{};
 v = a;
 }
 {
 struct A {};
 struct B {};
 struct L
 {
 int operator () (A) { return 100; }
 int operator () (B) { return 200; }
 };
 L v;
 using V = versatile< A, B >;
 static_assert(std::is_same< typename visitation::underlying_type< V >::type, A >());
 V a{A{}};
 assert(a.apply_visitor(v) == 100);
 V b{B{}};
 assert(b.apply_visitor(v) == 200);
 }
 {
 using V = versatile< int >;
 V a = +1;
 V b = -1;
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 a.swap(b);
 assert(static_cast< int & >(a) == -1);
 assert(static_cast< int & >(b) == +1);
 swap(a, b);
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 }
 {
 struct A {};
 struct B {};
 struct C {};
 struct D {};
 using AD = versatile< A, D >;
 using BA = versatile< B, A >;
 using CB = versatile< C, B >;
 using DC = versatile< D, C >;
 AD ad;
 BA ba;
 CB cb;
 DC dc;
 introspector introspector_;
 assert(apply_visitor(introspector_, ad, ba, cb, dc) == introspector_(A{}, B{}, C{}, D{}));
 AD da{D{}};
 BA ab{A{}};
 CB bc{B{}};
 DC cd{C{}};
 assert(apply_visitor(introspector_, da, ab, bc, cd) == introspector_(D{}, A{}, B{}, C{}));
 }
 {
 test< 15 >(); // Comment if known clang bug #19917 https://llvm.org/bugs/show_bug.cgi?id=19917 appeared in your case.
 }
 return EXIT_SUCCESS;
}
#pragma once
#include <type_traits>
#include <limits>
#include <utility>
#include <cassert>
namespace versatile
{
namespace type_traits
{
template< typename from, typename to >
struct copy_ref
{
 using type = to;
};
template< typename from, typename to >
struct copy_ref< from &, to >
{
 using type = to &;
};
template< typename from, typename to >
struct copy_ref< from &&, to >
{
 using type = to &&;
};
template< typename from, typename to >
struct copy_cv
{
 using type = to;
};
template< typename from, typename to >
struct copy_cv< volatile from const, to >
{
 using type = volatile to const;
};
template< typename from, typename to >
struct copy_cv< from const, to >
{
 using type = to const;
};
template< typename from, typename to >
struct copy_cv< volatile from, to >
{
 using type = volatile to;
};
}
template< typename from, typename to >
using copy_ref = typename type_traits::copy_ref< from, to >::type;
template< typename from, typename to >
using copy_cv = typename type_traits::copy_cv< from, to >::type;
template< typename from, typename to >
using copy_refcv = copy_ref< from, copy_cv< std::remove_reference_t< from >, to > >;
template< typename type, typename ...arguments >
using result_of = decltype(std::declval< type >()(std::declval< arguments >()...));
static constexpr std::size_t npos = std::numeric_limits< std::size_t >::max();
template< std::size_t which = npos, typename type = void >
struct indexed
{
 std::size_t which_ = which;
 type value_;
 template< typename ...arguments >
 explicit
 constexpr
 indexed(arguments &&... _arguments)
 : value_(std::forward< arguments >(_arguments)...)
 { ; }
};
template<>
struct indexed< npos, void >
{
 std::size_t which_ = npos;
};
template< typename ...types >
union versatile;
template<>
union versatile<>
{
 static constexpr std::size_t which_ = npos;
private :
 using head = indexed<>;
 head head_{};
public :
 template< typename type = void >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 return npos;
 }
 template< std::size_t _which >
 using at = void;
 using this_type = void;
 constexpr
 std::size_t
 which() const noexcept
 {
 return npos;
 }
 template< typename type = void >
 constexpr
 bool
 is_active() const noexcept
 {
 return false;
 }
 constexpr
 versatile() noexcept = default;
 constexpr
 void
 swap(versatile &) noexcept
 {
 return;
 }
};
template< typename first, typename ...rest >
union versatile< first, rest... >
{
 static_assert(std::is_standard_layout< first >(), "!");
 static constexpr std::size_t which_ = sizeof...(rest);
private :
 using head = indexed< which_, first >;
 using tail = versatile< rest... >;
 head head_;
 tail tail_;
public :
 template< typename type = first >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 if (std::is_same< type, first >()) {
 return which_;
 } else {
 return tail::template index< type >();
 }
 }
 template< std::size_t _which >
 using at = std::conditional_t< (_which == which_), first, typename tail::template at< _which > >;
 using this_type = first;
 constexpr
 std::size_t
 which() const noexcept
 {
 return head_.which_;
 }
 template< typename type = first >
 constexpr
 bool
 is_active() const noexcept
 {
 if (std::is_same< type, first >()) {
 return (which() == which_);
 } else {
 return tail_.template is_active< type >();
 }
 }
 ~versatile() noexcept(std::is_nothrow_destructible< first >() && std::is_nothrow_destructible< tail >())
 {
 if (is_active()) {
 head_.~head();
 } else {
 tail_.~tail();
 }
 }
private :
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::true_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< first, arguments... >())
 : head_(std::forward< arguments >(_arguments)...)
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::false_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< tail, arguments... >())
 : tail_(std::forward< arguments >(_arguments)...)
 { ; }
public :
 constexpr
 versatile() noexcept(std::is_nothrow_constructible< versatile, typename std::is_default_constructible< first >::type >())
 : versatile(typename std::is_default_constructible< first >::type{})
 { ; }
 template< typename argument >
 constexpr
 versatile(argument && _argument) noexcept(std::is_nothrow_constructible< tail, argument >())
 : versatile(std::false_type{}, std::forward< argument >(_argument))
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(arguments &&... _arguments) noexcept(std::is_nothrow_constructible< versatile, typename std::is_constructible< first, arguments... >::type, arguments... >())
 : versatile(typename std::is_constructible< first, arguments... >::type{}, std::forward< arguments >(_arguments)...)
 { ; }
 versatile(versatile const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile const && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 versatile(versatile && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 constexpr
 versatile(first const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first const && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile(first && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile &
 operator = (versatile const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile const && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (versatile && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (first const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first const && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 constexpr
 versatile &
 operator = (first && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 template< typename rhs >
 constexpr
 versatile &
 operator = (rhs && _rhs) noexcept(std::is_nothrow_assignable< tail &, rhs >())
 {
 tail_ = std::forward< rhs >(_rhs);
 return *this;
 }
 constexpr
 void
 swap(versatile & _other) noexcept
 {
 assert(_other.which() == which());
 if (is_active()) {
 using std::swap;
 swap(_other.head_.value_, head_.value_);
 } else {
 tail_.swap( _other.tail_);
 }
 }
 explicit
 constexpr
 operator first const & () const & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type const & () const & noexcept
 {
 return static_cast< type const & >(tail_);
 }
 explicit
 constexpr
 operator first & () & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type & () & noexcept
 {
 return static_cast< type & >(tail_);
 }
 explicit
 constexpr
 operator first const && () const && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type const && () const && noexcept
 {
 return static_cast< type const && >(tail_);
 }
 explicit
 constexpr
 operator first && () && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type && () && noexcept
 {
 return static_cast< type && >(tail_);
 }
private :
 template< typename type, typename result_type, typename visitor, typename visitable, typename ...arguments >
 static
 constexpr
 result_type
 caller(visitor && _visitor, visitable && _visitable, arguments &&... _arguments)
 {
 // There is known clang++ bug #19917. To avoid hard error here: replace "static_cast< type >(std::forward< visitable >(_visitable))" with "reinterpret_cast< type >(_visitable.head_.value_)".
 return std::forward< visitor >(_visitor)(static_cast< type >(std::forward< visitable >(_visitable)), std::forward< arguments >(_arguments)...);
 }
public :
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &, result_type, visitor, versatile const &, arguments... >, versatile::caller< rest const &, result_type, visitor, versatile const &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &, result_type, visitor, versatile &, arguments... >, versatile::caller< rest &, result_type, visitor, versatile &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &&, result_type, visitor, versatile const &&, arguments... >, versatile::caller< rest const &&, result_type, visitor, versatile const &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &&, result_type, visitor, versatile &&, arguments... >, versatile::caller< rest &&, result_type, visitor, versatile &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
};
template< typename ...types >
constexpr
void
swap(versatile< types... > & _lhs, versatile< types... > & _rhs) noexcept
{
 assert(_lhs.which() == _rhs.which());
 _lhs.swap(_rhs);
}
template< typename type >
struct is_versatile
 : std::false_type
{
};
template< typename ...types >
struct is_versatile< versatile< types... > >
 : std::true_type
{
};
template< typename versatile, typename type >
constexpr std::size_t index = versatile::template index< type >();
template< typename versatile, std::size_t index >
using at = typename versatile::template at< index >;
namespace visitation
{
template< typename type, bool = is_versatile< std::decay_t< type > >() >
struct underlying_type;
template< typename visitable >
struct underlying_type< visitable, true >
{
 using type = copy_refcv< visitable, typename std::decay_t< visitable >::this_type >;
};
template< typename general_type >
struct underlying_type< general_type, false >
{
 using type = general_type &&;
};
template< typename result_type, typename supervisitor, typename type, bool = is_versatile< std::decay_t< type > >() >
struct subvisitor;
template< typename result_type, typename supervisitor, typename visitable >
struct subvisitor< result_type, supervisitor, visitable, true >
{
 supervisitor && supervisitor_;
 visitable && visitable_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< visitable >(visitable_).apply_visitor(std::forward< supervisitor >(supervisitor_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename supervisitor, typename type >
struct subvisitor< result_type, supervisitor, type, false >
{
 supervisitor && supervisitor_;
 type && value_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< supervisitor >(supervisitor_)(std::forward< type >(value_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename ...visitables >
struct visitor_partially_applier;
template< typename result_type >
struct visitor_partially_applier< result_type >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor) const
 {
 return std::forward< visitor >(_visitor)();
 }
};
template< typename result_type, typename first, typename ...rest >
struct visitor_partially_applier< result_type, first, rest... >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor, first && _first, rest &&... _rest) const
 {
 subvisitor< result_type, visitor, first > subvisitor_{std::forward< visitor >(_visitor), std::forward< first >(_first)};
 return visitor_partially_applier< result_type, rest... >{}(subvisitor_, std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor, typename first, typename ...rest >
constexpr
decltype(auto)
apply_visitor(visitor && _visitor, first && _first, rest &&... _rest)
{
 using namespace visitation;
 using result_type = result_of< visitor, typename underlying_type< first >::type, typename underlying_type< rest >::type... >;
 return visitor_partially_applier< result_type, first, rest... >{}(std::forward< visitor >(_visitor), std::forward< first >(_first), std::forward< rest >(_rest)...);
}
namespace visitation
{
template< typename visitor >
struct delayed_visitor_applier
{
 visitor visitor_;
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor >
constexpr
visitation::delayed_visitor_applier< visitor >
apply_visitor(visitor && _visitor) noexcept
{
 return {std::forward< visitor >(_visitor)};
}
}
#include "versatile.hpp"
#include <string>
#include <array>
#include <utility>
#ifdef _DEBUG
#include <iostream>
#include <iomanip>
#endif
#include <cstdlib>
struct introspector
{
 template< typename ...types >
 std::string
 operator () (types...) const
 {
 return __PRETTY_FUNCTION__;
 }
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
namespace
{
template< std::size_t I >
struct T
{
};
struct P
{
 template< std::size_t ...I >
 std::array< std::size_t, sizeof...(I) >
 operator () (T< I > const &...) const
 {
 return {I...};
 }
};
template< std::size_t ...M, std::size_t ...N >
bool
invoke(std::index_sequence< M... > const &, std::index_sequence< N... > const &)
{
 using versatile::apply_visitor;
 using versatile::versatile;
 return (apply_visitor(P{}, versatile< T< M >... >{T< (N % sizeof...(M)) >{}}...) == std::array< std::size_t, sizeof...(N) >{(N % sizeof...(M))...});
}
template< std::size_t M, std::size_t N = M >
bool
test()
{
 return invoke(std::make_index_sequence< M >{}, std::make_index_sequence< N >{});
}
}
#pragma clang diagnostic pop
int
main()
{
 using namespace versatile;
 {
 using V0 = versatile<>;
 assert(!V0{}.is_active());
 using V1 = versatile< V0 >;
 assert(V1{}.which() == 0);
 assert((index< V1, V0 > == 0));
 using V2 = versatile< V1, V0 >;
 assert(V2{}.which() == 1);
 assert((index< V2, V1 > == 1));
 using V3 = versatile< V2, V1, V0 >;
 assert(V3{}.which() == 2);
 assert((index< V3, V2 > == 2));
 using V4 = versatile< V3, V2, V1, V0 >;
 assert(V4{}.which() == 3);
 assert((index< V4, V3 > == 3));
 using V5 = versatile< V4, V3, V2, V1, V0 >;
 assert(V5{}.which() == 4);
 assert((index< V5, V4 > == 4));
 static_assert(std::is_same< V4, at< V5, 4 > >(), "!");
 }
 {
 struct empty {};
 using V = versatile< empty, int, float, double, long double >;
 assert(V{}.is_active());
 assert(V{}.which() == 4);
 assert(V{0}.which() == 3);
 assert(V{1.0f}.which() == 2);
 assert(V{2.0}.which() == 1);
 assert(V{3.0L}.which() == 0);
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-member-function"
 struct A { explicit A(int, int) {} };
#pragma clang diagnostic pop
 struct B { explicit B(int, double) {} };
 using V = versatile< B, A, int >;
 V v0{1};
 assert((v0.which() == index< V, int >));
 V v1{1, 2};
 assert((v1.which() == index< V, B >)); // !
 V v2{1, 2.0};
 assert((v2.which() == index< V, B >));
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunneeded-member-function"
 struct A { ~A() noexcept(true) {} };
 struct B { ~B() noexcept(false) {} };
#pragma clang diagnostic pop
 using VA = versatile< A >;
 using VB = versatile< B >;
 using VAB = versatile< A, B >;
 static_assert(std::is_nothrow_destructible< A >(), "!");
 static_assert(!std::is_nothrow_destructible< B >(), "!");
 static_assert(std::is_nothrow_destructible< VA >(), "!");
 static_assert(!std::is_nothrow_destructible< VB >(), "!");
 static_assert(!std::is_nothrow_destructible< VAB >(), "!");
 }
 {
 struct A { A() {} A & operator = (A const &) = default; A & operator = (A &) = delete; };
 using V = versatile< A >;
 V v;
 A const a{};
 v = a;
 }
 {
 struct A {};
 struct B {};
 struct L
 {
 int operator () (A) { return 100; }
 int operator () (B) { return 200; }
 };
 L v;
 using V = versatile< A, B >;
 static_assert(std::is_same< typename visitation::underlying_type< V >::type, A >());
 V a{A{}};
 assert(a.apply_visitor(v) == 100);
 V b{B{}};
 assert(b.apply_visitor(v) == 200);
 }
 {
 using V = versatile< int >;
 V a = +1;
 V b = -1;
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 a.swap(b);
 assert(static_cast< int & >(a) == -1);
 assert(static_cast< int & >(b) == +1);
 swap(a, b);
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 }
 {
 struct A {};
 struct B {};
 struct C {};
 struct D {};
 using AD = versatile< A, D >;
 using BA = versatile< B, A >;
 using CB = versatile< C, B >;
 using DC = versatile< D, C >;
 AD ad;
 BA ba;
 CB cb;
 DC dc;
 introspector introspector_;
 assert(apply_visitor(introspector_, ad, ba, cb, dc) == introspector_(A{}, B{}, C{}, D{}));
 AD da{D{}};
 BA ab{A{}};
 CB bc{B{}};
 DC cd{C{}};
 assert(apply_visitor(introspector_, da, ab, bc, cd) == introspector_(D{}, A{}, B{}, C{}));
 }
 {
 test< 1 >(); // Comment if known clang bug #19917 https://llvm.org/bugs/show_bug.cgi?id=19917 appeared in your case.
 }
 return EXIT_SUCCESS;
}
#pragma once
#include <type_traits>
#include <limits>
#include <utility>
#include <cassert>
namespace versatile
{
namespace type_traits
{
template< typename from, typename to >
struct copy_ref
{
 using type = to;
};
template< typename from, typename to >
struct copy_ref< from &, to >
{
 using type = to &;
};
template< typename from, typename to >
struct copy_ref< from &&, to >
{
 using type = to &&;
};
template< typename from, typename to >
struct copy_cv
{
 using type = to;
};
template< typename from, typename to >
struct copy_cv< volatile from const, to >
{
 using type = volatile to const;
};
template< typename from, typename to >
struct copy_cv< from const, to >
{
 using type = to const;
};
template< typename from, typename to >
struct copy_cv< volatile from, to >
{
 using type = volatile to;
};
}
template< typename from, typename to >
using copy_ref = typename type_traits::copy_ref< from, to >::type;
template< typename from, typename to >
using copy_cv = typename type_traits::copy_cv< from, to >::type;
template< typename from, typename to >
using copy_refcv = copy_ref< from, copy_cv< std::remove_reference_t< from >, to > >;
template< typename type, typename ...arguments >
using result_of = decltype(std::declval< type >()(std::declval< arguments >()...));
static constexpr std::size_t npos = std::numeric_limits< std::size_t >::max();
template< std::size_t which = npos, typename type = void >
struct indexed
{
 std::size_t which_ = which;
 type value_;
 template< typename ...arguments >
 explicit
 constexpr
 indexed(arguments &&... _arguments)
 : value_(std::forward< arguments >(_arguments)...)
 { ; }
};
template<>
struct indexed< npos, void >
{
 std::size_t which_ = npos;
};
template< typename ...types >
union versatile;
template<>
union versatile<>
{
 static constexpr std::size_t which_ = npos;
private :
 using head = indexed<>;
 head head_{};
public :
 template< typename type = void >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 return npos;
 }
 template< std::size_t _which >
 using at = void;
 using this_type = void;
 constexpr
 std::size_t
 which() const noexcept
 {
 return npos;
 }
 template< typename type = void >
 constexpr
 bool
 is_active() const noexcept
 {
 return false;
 }
 constexpr
 versatile() noexcept = default;
 constexpr
 void
 swap(versatile &) noexcept
 {
 return;
 }
};
template< typename first, typename ...rest >
union versatile< first, rest... >
{
 static_assert(std::is_standard_layout< first >(), "!");
 static constexpr std::size_t which_ = sizeof...(rest);
private :
 using head = indexed< which_, first >;
 using tail = versatile< rest... >;
 head head_;
 tail tail_;
public :
 template< typename type = first >
 static
 constexpr
 std::size_t
 index() noexcept
 {
 if (std::is_same< type, first >()) {
 return which_;
 } else {
 return tail::template index< type >();
 }
 }
 template< std::size_t _which >
 using at = std::conditional_t< (_which == which_), first, typename tail::template at< _which > >;
 using this_type = first;
 constexpr
 std::size_t
 which() const noexcept
 {
 return head_.which_;
 }
 template< typename type = first >
 constexpr
 bool
 is_active() const noexcept
 {
 if (std::is_same< type, first >()) {
 return (which() == which_);
 } else {
 return tail_.template is_active< type >();
 }
 }
 ~versatile() noexcept(std::is_nothrow_destructible< first >() && std::is_nothrow_destructible< tail >())
 {
 if (is_active()) {
 head_.~head();
 } else {
 tail_.~tail();
 }
 }
private :
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::true_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< first, arguments... >())
 : head_(std::forward< arguments >(_arguments)...)
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(std::false_type, arguments &&... _arguments) noexcept(std::is_nothrow_constructible< tail, arguments... >())
 : tail_(std::forward< arguments >(_arguments)...)
 { ; }
public :
 constexpr
 versatile() noexcept(std::is_nothrow_constructible< versatile, typename std::is_default_constructible< first >::type >())
 : versatile(typename std::is_default_constructible< first >::type{})
 { ; }
 template< typename argument >
 constexpr
 versatile(argument && _argument) noexcept(std::is_nothrow_constructible< tail, argument >())
 : versatile(std::false_type{}, std::forward< argument >(_argument))
 { ; }
 template< typename ...arguments >
 explicit
 constexpr
 versatile(arguments &&... _arguments) noexcept(std::is_nothrow_constructible< versatile, typename std::is_constructible< first, arguments... >::type, arguments... >())
 : versatile(typename std::is_constructible< first, arguments... >::type{}, std::forward< arguments >(_arguments)...)
 { ; }
 versatile(versatile const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile & _rhs) noexcept(std::is_nothrow_copy_constructible< first >() && std::is_nothrow_copy_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(_rhs.head_.value_);
 } else {
 ::new (&tail_) tail(_rhs.tail_);
 }
 }
 versatile(versatile const && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 versatile(versatile && _rhs) noexcept(std::is_nothrow_move_constructible< first >() && std::is_nothrow_move_constructible< tail >())
 {
 if (_rhs.which() == which_) {
 ::new (&head_) head(std::move(_rhs.head_.value_));
 } else {
 ::new (&tail_) tail(std::move(_rhs.tail_));
 }
 }
 constexpr
 versatile(first const & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first & _rhs) noexcept(std::is_nothrow_copy_constructible< first >())
 : head_(_rhs)
 { ; }
 constexpr
 versatile(first const && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile(first && _rhs) noexcept(std::is_nothrow_move_constructible< first >())
 : head_(std::move(_rhs))
 { ; }
 constexpr
 versatile &
 operator = (versatile const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile & _rhs) noexcept(std::is_nothrow_copy_assignable< first >() && std::is_nothrow_copy_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = _rhs.tail_;
 return *this;
 }
 return operator = (_rhs.head_.value_);
 }
 constexpr
 versatile &
 operator = (versatile const && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (versatile && _rhs) noexcept(std::is_nothrow_move_assignable< first >() && std::is_nothrow_move_assignable< tail >())
 {
 assert(_rhs.which() == which());
 if (_rhs.which() != which_) {
 tail_ = std::move(_rhs.tail_);
 return *this;
 }
 return operator = (std::move(_rhs.head_.value_));
 }
 constexpr
 versatile &
 operator = (first const & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first & _rhs) noexcept(std::is_nothrow_copy_assignable< first >())
 {
 operator first & () = _rhs;
 return *this;
 }
 constexpr
 versatile &
 operator = (first const && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 constexpr
 versatile &
 operator = (first && _rhs) noexcept(std::is_nothrow_move_assignable< first >())
 {
 operator first & () = std::move(_rhs);
 return *this;
 }
 template< typename rhs >
 constexpr
 versatile &
 operator = (rhs && _rhs) noexcept(std::is_nothrow_assignable< tail &, rhs >())
 {
 tail_ = std::forward< rhs >(_rhs);
 return *this;
 }
 constexpr
 void
 swap(versatile & _other) noexcept
 {
 assert(_other.which() == which());
 if (is_active()) {
 using std::swap;
 swap(_other.head_.value_, head_.value_);
 } else {
 tail_.swap( _other.tail_);
 }
 }
 explicit
 constexpr
 operator first const & () const & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type const & () const & noexcept
 {
 return static_cast< type const & >(tail_);
 }
 explicit
 constexpr
 operator first & () & noexcept
 {
 assert(is_active());
 return head_.value_;
 }
 template< typename type >
 explicit
 constexpr
 operator type & () & noexcept
 {
 return static_cast< type & >(tail_);
 }
 explicit
 constexpr
 operator first const && () const && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type const && () const && noexcept
 {
 return static_cast< type const && >(tail_);
 }
 explicit
 constexpr
 operator first && () && noexcept
 {
 assert(is_active());
 return std::move(head_.value_);
 }
 template< typename type >
 explicit
 constexpr
 operator type && () && noexcept
 {
 return static_cast< type && >(tail_);
 }
private :
 template< typename type, typename result_type, typename visitor, typename visitable, typename ...arguments >
 static
 constexpr
 result_type
 caller(visitor && _visitor, visitable && _visitable, arguments &&... _arguments)
 {
 // There is known clang++ bug #19917 for static_cast to rvalue reference. To avoid hard error here: replace "static_cast< type >(std::forward< visitable >(_visitable))" with "reinterpret_cast< type >(_visitable.head_.value_)".
 return std::forward< visitor >(_visitor)(static_cast< type >(std::forward< visitable >(_visitable)), std::forward< arguments >(_arguments)...);
 }
public :
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &, result_type, visitor, versatile const &, arguments... >, versatile::caller< rest const &, result_type, visitor, versatile const &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile & _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &, result_type, visitor, versatile &, arguments... >, versatile::caller< rest &, result_type, visitor, versatile &, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), *this, std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) const &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile const && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first const &&, result_type, visitor, versatile const &&, arguments... >, versatile::caller< rest const &&, result_type, visitor, versatile const &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
 template< typename visitor, typename ...arguments >
 decltype(auto)
 apply_visitor(visitor && _visitor, arguments &&... _arguments) &&
 {
 using result_type = result_of< visitor, first, arguments... >;
 using caller_type = result_type (*)(visitor && _visitor, versatile && _visitable, arguments &&... _arguments);
 static constexpr caller_type dispatcher_[1 + sizeof...(rest)] = {versatile::caller< first &&, result_type, visitor, versatile &&, arguments... >, versatile::caller< rest &&, result_type, visitor, versatile &&, arguments... >...};
 return dispatcher_[which_ - which()](std::forward< visitor >(_visitor), std::move(*this), std::forward< arguments >(_arguments)...);
 }
};
template< typename ...types >
constexpr
void
swap(versatile< types... > & _lhs, versatile< types... > & _rhs) noexcept
{
 assert(_lhs.which() == _rhs.which());
 _lhs.swap(_rhs);
}
template< typename type >
struct is_versatile
 : std::false_type
{
};
template< typename ...types >
struct is_versatile< versatile< types... > >
 : std::true_type
{
};
template< typename versatile, typename type >
constexpr std::size_t index = versatile::template index< type >();
template< typename versatile, std::size_t index >
using at = typename versatile::template at< index >;
namespace visitation
{
template< typename type, bool = is_versatile< std::decay_t< type > >() >
struct underlying_type;
template< typename visitable >
struct underlying_type< visitable, true >
{
 using type = copy_refcv< visitable, typename std::decay_t< visitable >::this_type >;
};
template< typename general_type >
struct underlying_type< general_type, false >
{
 using type = general_type &&;
};
template< typename result_type, typename supervisitor, typename type, bool = is_versatile< std::decay_t< type > >() >
struct subvisitor;
template< typename result_type, typename supervisitor, typename visitable >
struct subvisitor< result_type, supervisitor, visitable, true >
{
 supervisitor && supervisitor_;
 visitable && visitable_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< visitable >(visitable_).apply_visitor(std::forward< supervisitor >(supervisitor_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename supervisitor, typename type >
struct subvisitor< result_type, supervisitor, type, false >
{
 supervisitor && supervisitor_;
 type && value_;
 template< typename ...visited >
 constexpr
 result_type
 operator () (visited &&... _visited) const
 {
 return std::forward< supervisitor >(supervisitor_)(std::forward< type >(value_), std::forward< visited >(_visited)...);
 }
};
template< typename result_type, typename ...visitables >
struct visitor_partially_applier;
template< typename result_type >
struct visitor_partially_applier< result_type >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor) const
 {
 return std::forward< visitor >(_visitor)();
 }
};
template< typename result_type, typename first, typename ...rest >
struct visitor_partially_applier< result_type, first, rest... >
{
 template< typename visitor >
 constexpr
 result_type
 operator () (visitor && _visitor, first && _first, rest &&... _rest) const
 {
 subvisitor< result_type, visitor, first > subvisitor_{std::forward< visitor >(_visitor), std::forward< first >(_first)};
 return visitor_partially_applier< result_type, rest... >{}(subvisitor_, std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor, typename first, typename ...rest >
constexpr
decltype(auto)
apply_visitor(visitor && _visitor, first && _first, rest &&... _rest)
{
 using namespace visitation;
 using result_type = result_of< visitor, typename underlying_type< first >::type, typename underlying_type< rest >::type... >;
 return visitor_partially_applier< result_type, first, rest... >{}(std::forward< visitor >(_visitor), std::forward< first >(_first), std::forward< rest >(_rest)...);
}
namespace visitation
{
template< typename visitor >
struct delayed_visitor_applier
{
 visitor visitor_;
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &
 {
 return apply_visitor(visitor_, std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) const &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
 template< typename first, typename ...rest >
 decltype(auto)
 operator () (first && _first, rest &&... _rest) &&
 {
 return apply_visitor(std::move(visitor_), std::forward< first >(_first), std::forward< rest >(_rest)...);
 }
};
}
template< typename visitor >
constexpr
visitation::delayed_visitor_applier< visitor >
apply_visitor(visitor && _visitor) noexcept
{
 return {std::forward< visitor >(_visitor)};
}
}
#include "versatile.hpp"
#include <string>
#include <array>
#include <utility>
#ifdef _DEBUG
#include <iostream>
#include <iomanip>
#endif
#include <cstdlib>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
namespace
{
struct introspector
{
 template< typename ...types >
 std::string
 operator () (types...) const
 {
 return __PRETTY_FUNCTION__;
 }
};
template< std::size_t I >
struct T
{
};
struct visitor
{
 template< std::size_t ...I >
 std::array< std::size_t, sizeof...(I) >
 operator () (T< I > const &...) const
 {
 return {I...};
 }
};
template< typename L, typename ...R >
bool
lvaluelizer(L const & _lhs, R const &... _rhs) // To avoid known clang bug #19917 https://llvm.org/bugs/show_bug.cgi?id=19917 makes all parametres lvalues.
{
 using versatile::apply_visitor;
 return (_lhs == apply_visitor(visitor{}, _rhs...));
}
template< std::size_t ...M, std::size_t ...N >
bool
invoke(std::index_sequence< M... > const &, std::index_sequence< N... > const &)
{
 using versatile::versatile;
 return lvaluelizer(std::array< std::size_t, sizeof...(N) >{(N % sizeof...(M))...}, versatile< T< M >... >{T< (N % sizeof...(M)) >{}}...);
}
template< std::size_t M, std::size_t N = M >
bool
test()
{
 return invoke(std::make_index_sequence< M >{}, std::make_index_sequence< N >{});
}
}
#pragma clang diagnostic pop
int
main()
{
 using namespace versatile;
 {
 using V0 = versatile<>;
 assert(!V0{}.is_active());
 using V1 = versatile< V0 >;
 assert(V1{}.which() == 0);
 assert((index< V1, V0 > == 0));
 using V2 = versatile< V1, V0 >;
 assert(V2{}.which() == 1);
 assert((index< V2, V1 > == 1));
 using V3 = versatile< V2, V1, V0 >;
 assert(V3{}.which() == 2);
 assert((index< V3, V2 > == 2));
 using V4 = versatile< V3, V2, V1, V0 >;
 assert(V4{}.which() == 3);
 assert((index< V4, V3 > == 3));
 using V5 = versatile< V4, V3, V2, V1, V0 >;
 assert(V5{}.which() == 4);
 assert((index< V5, V4 > == 4));
 static_assert(std::is_same< V4, at< V5, 4 > >(), "!");
 }
 {
 struct empty {};
 using V = versatile< empty, int, float, double, long double >;
 assert(V{}.is_active());
 assert(V{}.which() == 4);
 assert(V{0}.which() == 3);
 assert(V{1.0f}.which() == 2);
 assert(V{2.0}.which() == 1);
 assert(V{3.0L}.which() == 0);
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-member-function"
 struct A { explicit A(int, int) {} };
#pragma clang diagnostic pop
 struct B { explicit B(int, double) {} };
 using V = versatile< B, A, int >;
 V v0{1};
 assert((v0.which() == index< V, int >));
 V v1{1, 2};
 assert((v1.which() == index< V, B >)); // !
 V v2{1, 2.0};
 assert((v2.which() == index< V, B >));
 }
 {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunneeded-member-function"
 struct A { ~A() noexcept(true) {} };
 struct B { ~B() noexcept(false) {} };
#pragma clang diagnostic pop
 using VA = versatile< A >;
 using VB = versatile< B >;
 using VAB = versatile< A, B >;
 static_assert(std::is_nothrow_destructible< A >(), "!");
 static_assert(!std::is_nothrow_destructible< B >(), "!");
 static_assert(std::is_nothrow_destructible< VA >(), "!");
 static_assert(!std::is_nothrow_destructible< VB >(), "!");
 static_assert(!std::is_nothrow_destructible< VAB >(), "!");
 }
 {
 struct A { A() {} A & operator = (A const &) = default; A & operator = (A &) = delete; };
 using V = versatile< A >;
 V v;
 A const a{};
 v = a;
 }
 {
 struct A {};
 struct B {};
 struct L
 {
 int operator () (A) { return 100; }
 int operator () (B) { return 200; }
 };
 L v;
 using V = versatile< A, B >;
 static_assert(std::is_same< typename visitation::underlying_type< V >::type, A >());
 V a{A{}};
 assert(a.apply_visitor(v) == 100);
 V b{B{}};
 assert(b.apply_visitor(v) == 200);
 }
 {
 using V = versatile< int >;
 V a = +1;
 V b = -1;
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 a.swap(b);
 assert(static_cast< int & >(a) == -1);
 assert(static_cast< int & >(b) == +1);
 swap(a, b);
 assert(static_cast< int & >(a) == +1);
 assert(static_cast< int & >(b) == -1);
 }
 {
 struct A {};
 struct B {};
 struct C {};
 struct D {};
 using AD = versatile< A, D >;
 using BA = versatile< B, A >;
 using CB = versatile< C, B >;
 using DC = versatile< D, C >;
 AD ad;
 BA ba;
 CB cb;
 DC dc;
 introspector introspector_;
 assert(apply_visitor(introspector_, ad, ba, cb, dc) == introspector_(A{}, B{}, C{}, D{}));
 AD da{D{}};
 BA ab{A{}};
 CB bc{B{}};
 DC cd{C{}};
 assert(apply_visitor(introspector_, da, ab, bc, cd) == introspector_(D{}, A{}, B{}, C{}));
 }
 {
 test< 5 >();
 }
 return EXIT_SUCCESS;
}
added 15996 characters in body
Source Link
Loading
added 4422 characters in body
Source Link
Loading
deleted 189 characters in body
Source Link
Loading
deleted 152 characters in body
Source Link
Loading
added 18 characters in body
Source Link
Loading
I made changes because the question has no answer till the moment.
Source Link
Loading
Tweeted twitter.com/#!/StackCodeReview/status/581081104179920897
added 623 characters in body
Source Link
Loading
added 53 characters in body
Source Link
Loading
Source Link
Loading
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /