Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <boost/mpl/list.hpp>
- #include <memory>
- #include <type_traits>
- #include <exception>
- #include <cassert>
- template< typename type, type ...values >
- struct max_value;
- template< typename type, type last >
- struct max_value< type, last >
- {
- static constexpr type const value = last;
- };
- template< typename type, type first, type ...rest >
- struct max_value< type, first, rest... >
- {
- static constexpr type const value = (first < max_value< type, rest... >::value) ? max_value< type, rest... >::value : first;
- };
- template< int base, bool ...results >
- struct index_of_first_truth;
- template< int base >
- struct index_of_first_truth< base >
- {
- static constexpr int const value = -1;
- };
- template< int base, bool ...rest >
- struct index_of_first_truth< base, false, rest... >
- {
- static constexpr int const value = index_of_first_truth< base + 1, rest... >::value;
- };
- template< int base, bool ...rest >
- struct index_of_first_truth< base, true, rest... >
- {
- static constexpr int const value = base;
- };
- template< int base, int index, typename ...types >
- struct type_by_index;
- template< int found, typename last >
- struct type_by_index< found, found, last >
- {
- using type = last;
- };
- template< int base, int index, typename last >
- struct type_by_index< base, index, last >
- {
- static_assert(!(base < index),
- "valid index should be less than the number of types");
- static_assert(!(index < 0),
- "valid index should not be negative");
- };
- template< int base, int index, typename first, typename ...rest >
- struct type_by_index< base, index, first, rest... >
- {
- using type = typename type_by_index< base + 1, index, rest... >::type;
- };
- template< int found, typename first, typename ...rest >
- struct type_by_index< found, found, first, rest... >
- {
- using type = first;
- };
- template< typename ...types >
- struct is_all_the_same;
- template< typename last >
- struct is_all_the_same< last >
- {
- static constexpr bool const value = true;
- };
- template< typename next, typename ...rest >
- struct is_all_the_same< next, next, rest... >
- {
- static constexpr bool const value = is_all_the_same< next, rest... >::value;
- };
- template< typename first, typename second, typename ...rest >
- struct is_all_the_same< first, second, rest... >
- {
- static constexpr bool const value = false;
- };
- struct bad_get
- : std::exception
- {
- virtual
- const char *
- what() const noexcept
- {
- return "bad_get: failed value get using get";
- }
- };
- template< typename first, typename ...rest >
- struct variant
- {
- using types = typename boost::mpl::list< first, rest... >::type;
- // for switch/case/get of special cases without using of visitors
- template< typename type >
- using index_of_type = index_of_first_truth< 0, std::is_same< first, type >::value, std::is_same< rest, type >::value... >;
- private :
- template< typename ...arguments >
- using index_of_first_type_constructible_from = index_of_first_truth< 0, std::is_constructible< first, arguments... >::value, std::is_constructible< rest, arguments... >::value... >;
- template< typename ...arguments >
- using first_type_constructible_from = typename type_by_index< 0, index_of_first_type_constructible_from< arguments... >::value, first, rest... >::type;
- using storage_type = typename std::aligned_storage< max_value< decltype(sizeof(first)), sizeof(first), sizeof(rest)... >::value, max_value< decltype(alignof(first)), alignof(first), alignof(rest)... >::value >::type;
- storage_type storage_;
- int which_ = -1;
- template< typename type, typename visitor, typename ...arguments >
- typename std::result_of< visitor(type const &, arguments &&...) >::type
- const_lvalue_caller(visitor && _visitor, arguments &&... _arguments) const &
- {
- return std::forward< visitor >(_visitor)(reinterpret_cast< type const & >(storage_), std::forward< arguments >(_arguments)...);
- }
- template< typename type, typename visitor, typename ...arguments >
- typename std::result_of< visitor(type &, arguments &&...) >::type
- lvalue_caller(visitor && _visitor, arguments &&... _arguments) &
- {
- return std::forward< visitor >(_visitor)(reinterpret_cast< type & >(storage_), std::forward< arguments >(_arguments)...);
- }
- template< typename type, typename visitor, typename ...arguments >
- typename std::result_of< visitor(type &&, arguments &&...) >::type
- rvalue_caller(visitor && _visitor, arguments &&... _arguments) &&
- {
- return std::forward< visitor >(_visitor)(reinterpret_cast< type && >(storage_), std::forward< arguments >(_arguments)...);
- }
- template< typename type, typename ...arguments >
- auto &
- construct(arguments &&... _arguments)
- {
- using clean_type = typename std::remove_reference< typename std::remove_const< type >::type >::type;
- constexpr int const index_ = index_of_type< clean_type >::value;
- static_assert(!(index_ < 0),
- "type is not listed");
- which_ = index_;
- return *new (&storage_) clean_type{std::forward< arguments >(_arguments)...}; // curly braces to gain warning about narrowing of some types
- }
- struct destroyer
- {
- template< typename type >
- void
- operator () (type & _value) const
- {
- _value.~type();
- }
- };
- struct constructor
- {
- template< typename type >
- void
- operator () (type && _value, variant & _destination) const
- {
- _destination.construct< type >(std::forward< type >(_value));
- }
- template< typename type >
- void
- operator () (type && _value, variant && _destination) const
- {
- _destination.construct< type >(std::forward< type >(_value));
- }
- };
- struct assigner
- {
- template< typename type >
- void
- operator () (type && _value, variant & _destination) const
- {
- using clean_type = typename std::remove_reference< typename std::remove_const< type >::type >::type;
- _destination.get< clean_type >() = std::forward< type >(_value);
- }
- };
- public :
- variant()
- {
- construct< first >();
- }
- virtual
- ~variant() noexcept
- {
- apply_visitor(destroyer());
- }
- variant(variant const & _rhs)
- {
- _rhs.apply_visitor(constructor(), *this);
- }
- variant(variant & _rhs)
- {
- _rhs.apply_visitor(constructor(), *this);
- }
- variant(variant const && _rhs) = delete;
- variant(variant && _rhs) noexcept
- {
- std::move(_rhs).apply_visitor(constructor(), *this);
- }
- variant &
- operator = (variant const & _rhs)
- {
- _rhs.apply_visitor(assigner(), *this);
- return *this;
- }
- variant &
- operator = (variant & _rhs)
- {
- _rhs.apply_visitor(assigner(), *this);
- return *this;
- }
- variant &
- operator = (variant const && _rhs) = delete;
- variant &
- operator = (variant && _rhs)
- {
- std::move(_rhs).apply_visitor(assigner(), *this);
- return *this;
- }
- template< typename type,
- typename = typename std::enable_if< !(index_of_type< typename std::remove_reference< typename std::remove_const< type >::type >::type >::value < 0) >::type >
- variant(type && _value)
- {
- construct< type >(std::forward< type >(_value));
- }
- template< typename ...arguments >
- variant(arguments &&... _arguments) // constructs value of first type, which is constructible form specified pack of arguments
- {
- using type = first_type_constructible_from< arguments... >;
- construct< type >(std::forward< arguments >(_arguments)...);
- }
- int
- which() const
- {
- return which_;
- }
- template< int index >
- auto &
- get()
- {
- static_assert(!(index < 0),
- "index is negative");
- static_assert((index < (sizeof...(rest) + 1)),
- "index is too large");
- if (which_ != index) {
- throw bad_get();
- } else {
- using type = type_by_index< 0, index, first, rest... >;
- return reinterpret_cast< type & >(storage_);
- }
- }
- template< int index >
- auto const &
- get() const
- {
- static_assert(!(index < 0),
- "index is negative");
- static_assert((index < (sizeof...(rest) + 1)),
- "index is too large");
- if (which_ != index) {
- throw bad_get();
- } else {
- using type = type_by_index< 0, index, first, rest... >;
- return reinterpret_cast< type const & >(storage_);
- }
- }
- template< typename type >
- type &
- get()
- {
- constexpr int const index_ = index_of_type< type >::value;
- static_assert(!(index_ < 0),
- "the type is not listed");
- if (which_ != index_) {
- throw bad_get();
- } else {
- return reinterpret_cast< type & >(storage_);
- }
- }
- template< typename type >
- type const &
- get() const
- {
- constexpr int const index_ = index_of_type< type >::value;
- static_assert(!(index_ < 0),
- "the type is not listed");
- if (which_ != index_) {
- throw bad_get();
- } else {
- return reinterpret_cast< type const & >(storage_);
- }
- }
- template< typename visitor, typename ...arguments >
- auto
- apply_visitor(visitor && _visitor, arguments &&... _arguments) const &
- {
- static_assert(is_all_the_same< typename std::result_of< visitor(first const &, arguments &&...) >::type, typename std::result_of< visitor(rest const &, arguments &&...) >::type... >::value,
- "non-identical return types in visitor");
- using result_type = typename std::result_of< visitor(first const &, arguments &&...) >::type;
- using caller_type = result_type (variant::*)(visitor &&, arguments &&...) const &;
- static caller_type dispatcher_[1 + sizeof...(rest)] =
- {&variant::const_lvalue_caller< first, visitor, arguments... >, &variant::const_lvalue_caller< rest, visitor, arguments... >...};
- return (*this.*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
- }
- template< typename visitor, typename ...arguments >
- auto
- apply_visitor(visitor && _visitor, arguments &&... _arguments) &
- {
- static_assert(is_all_the_same< typename std::result_of< visitor(first &, arguments &&...) >::type, typename std::result_of< visitor(rest &, arguments &&...) >::type... >::value,
- "non-identical return types in visitor");
- using result_type = typename std::result_of< visitor(first &, arguments &&...) >::type;
- using caller_type = result_type (variant::*)(visitor &&, arguments &&...) &;
- static caller_type dispatcher_[1 + sizeof...(rest)] =
- {&variant::lvalue_caller< first, visitor, arguments... >, &variant::lvalue_caller< rest, visitor, arguments... >...};
- return (*this.*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
- }
- template< typename visitor, typename ...arguments >
- auto
- apply_visitor(visitor && _visitor, arguments &&... _arguments) &&
- {
- static_assert(is_all_the_same< typename std::result_of< visitor(first &&, arguments &&...) >::type, typename std::result_of< visitor(rest &&, arguments &&...) >::type... >::value,
- "non-identical return types in visitor");
- using result_type = typename std::result_of< visitor(first &&, arguments &&...) >::type;
- using caller_type = result_type (variant::*)(visitor &&, arguments &&...) &&;
- static caller_type dispatcher_[1 + sizeof...(rest)] =
- {&variant::rvalue_caller< first, visitor, arguments... >, &variant::rvalue_caller< rest, visitor, arguments... >...};
- return (std::move(*this).*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
- }
- };
- template< typename variant, typename ...arguments >
- variant
- make_variant(arguments &&... _arguments)
- {
- return {std::forward< arguments >(_arguments)...};
- }
- template< typename type, typename variant >
- type const &
- get(variant const & _variant)
- {
- return _variant.get< type >();
- }
- template< typename type, typename variant >
- type &
- get(variant & _variant)
- {
- return _variant.get< type >();
- }
- ////////////////////////////////////////////// .cpp
- #include "variant.hpp"
- #include <iostream>
- #include <cstdlib>
- #include <boost/variant.hpp>
- using A = struct {};
- struct printer
- {
- void
- operator () (int const & x) const
- {
- std::cout << "int const & = " << x << std::endl;
- }
- void
- operator () (int & x) const
- {
- std::cout << "int & = " << x << std::endl;
- }
- void
- operator () (int && x) const
- {
- std::cout << "int && = " << x << std::endl;
- }
- void
- //float
- operator () (float x) const
- {
- std::cout << "float = " << x << std::endl;
- //return 1.0f;
- }
- void
- operator () (double x) const
- {
- std::cout << "double = " << x << std::endl;
- }
- void
- operator () (long double x) const
- {
- std::cout << "long double = " << x << std::endl;
- }
- long
- operator () (long & x, A &&)
- {
- std::cout << "long &, A && = " << x << std::endl;
- return 0l;
- }
- long
- operator () (long & x)
- {
- std::cout << "long & = " << x << std::endl;
- return 0l;
- }
- void
- operator () (unsigned && x) const
- {
- std::cout << "unsigned && = " << x << std::endl;
- }
- };
- struct B
- {
- B() { std::cout << "B()" << std::endl; }
- B(int) { std::cout << "B(int)" << std::endl; }
- B(B &) { std::cout << "B(B &)" << std::endl; }
- B(B const &) { std::cout << "B(B const &)" << std::endl; }
- B(B &&) { std::cout << "B(B &&)" << std::endl; }
- B(B const &&) { std::cout << "B(B const &&)" << std::endl; }
- B & operator = (B &) { std::cout << "operator = (B &)" << std::endl; return *this; }
- B & operator = (B const &) { std::cout << "operator = (B const &)" << std::endl; return *this; }
- B & operator = (B &&) { std::cout << "operator = (B &&)" << std::endl; return *this; }
- B & operator = (B const &&) { std::cout << "operator = (B const &&)" << std::endl; return *this; }
- virtual
- ~B() noexcept
- { std::cout << "~B()" << std::endl; }
- };
- int main()
- {
- printer const printer_;
- variant< int, double > const v(1);
- std::cout << v.which() << std::endl;
- v.apply_visitor(printer());
- variant< int, double > v1(1.1);
- std::cout << v1.which() << std::endl;
- v1.apply_visitor(printer());
- variant< int, float, long double > const v2(222);
- v2.apply_visitor(printer_);
- variant< long > v4(111l);
- printer vp_;
- v4.apply_visitor(vp_, A());
- v4.apply_visitor(vp_);
- variant< unsigned >(7u).apply_visitor(printer_);
- variant< int >(33).apply_visitor(printer_);
- std::cout << std::endl;
- {
- using V = variant< B >;
- {
- V a = B();
- std::cout << "!" << std::endl;
- }
- std::cout << "----" << std::endl;
- {
- B b;
- V a = b;
- std::cout << "!" << std::endl;
- }
- std::cout << "----" << std::endl;
- {
- B const b;
- V a = b;
- std::cout << "!" << std::endl;
- }
- }
- {
- int a = 0;
- boost::variant< int const * > v6(&a);
- variant< int * > v3(&a);
- make_variant< variant< int const * > >(&a);
- //int const b = 1;
- //make_variant< variant< int * > >(&b);
- }
- {
- using const_variant = variant< int > const;
- std::move(const_variant(123)).apply_visitor(printer_); // no ambiguity
- }
- {
- //variant< int > v(1.0); // produces warning 'narrowing'
- }
- {
- variant< int > v6(1);
- v6 = 23;
- v6.apply_visitor(printer_);
- }
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment