text: #ifndef PYTHONIC_TYPES_VARIANT_FUNCTOR_HPP
  #define PYTHONIC_TYPES_VARIANT_FUNCTOR_HPP
  
  #include "pythonic/include/types/variant_functor.hpp"
  #include "pythonic/utils/meta.hpp"
  
  #include <utility>
  #include <cassert>
  
  PYTHONIC_NS_BEGIN
  
  namespace types
  {
  
    namespace details
    {
  
      template <class Type>
      variant_functor_impl<Type>::variant_functor_impl(char mem[], Type const &t)
          : fun(new (mem) Type(t))
      {
      }
  
      template <class Type>
      template <class OtherType>
      variant_functor_impl<Type>::variant_functor_impl(char mem[],
                                                       OtherType const &t)
          : fun(nullptr)
      {
      }
  
      template <class Type>
      variant_functor_impl<Type>::variant_functor_impl(
          char mem[], variant_functor_impl<Type> const &t)
          : fun(t.fun ? new (mem) Type(*t.fun) : nullptr)
      {
      }
  
      template <class Type>
      template <class... OtherTypes>
      variant_functor_impl<Type>::variant_functor_impl(
          char mem[], variant_functor_impl<Type, OtherTypes...> const &t)
          : variant_functor_impl(mem, t.head)
      {
      }
  
      template <class Type>
      template <class OtherType, class... OtherTypes>
      variant_functor_impl<Type>::variant_functor_impl(
          char mem[], variant_functor_impl<OtherType, OtherTypes...> const &t)
          : variant_functor_impl(mem, t.tail)
      {
      }
  
      template <class Type>
      void
      variant_functor_impl<Type>::assign(char mem[],
                                         variant_functor_impl<Type> const &other)
      {
        if (fun != nullptr)
          fun->~Type();
        if (other.fun)
          fun = new (mem) Type(*other.fun);
      }
      template <class Type>
      void variant_functor_impl<Type>::assign(char mem[],
                                              variant_functor<Type> const &other)
      {
        assign(mem, static_cast<variant_functor_impl<Type> const &>(other));
      }
  
      template <class Type>
      template <class OT0, class OT1, class... OtherTypes>
      void variant_functor_impl<Type>::assign(
          char mem[], variant_functor_impl<OT0, OT1, OtherTypes...> const &other)
      {
        assign(mem, other.head);
        assign(mem, other.tail);
      }
  
      template <class Type>
      template <class OT0, class OT1, class... OtherTypes>
      void variant_functor_impl<Type>::assign(
          char mem[], variant_functor<OT0, OT1, OtherTypes...> const &other)
      {
        assign(mem,
               static_cast<variant_functor_impl<OT0, OT1, OtherTypes...> const &>(
                   other));
      }
  
      template <class Type>
      template <class OtherType>
      void variant_functor_impl<Type>::assign(
          char mem[], variant_functor_impl<OtherType> const &other)
      {
      }
  
      template <class Type>
      template <class OtherType>
      void
      variant_functor_impl<Type>::assign(char mem[],
                                         variant_functor<OtherType> const &other)
      {
      }
  
      template <class Type>
      void variant_functor_impl<Type>::assign(char mem[], Type const &other)
      {
        if (fun != nullptr)
          fun->~Type();
        fun = new (mem) Type(other);
      }
  
      template <class Type>
      variant_functor_impl<Type>::~variant_functor_impl()
      {
        if (fun != nullptr)
          fun->~Type();
      }
  
      template <class Type>
      template <class OtherType>
      void variant_functor_impl<Type>::assign(char mem[], OtherType const &other)
      {
      }
  
      template <class Type>
      template <class... Args>
      auto variant_functor_impl<Type>::operator()(Args &&... args)
          -> decltype(std::declval<Type>()(std::forward<Args>(args)...))
      {
        assert(fun && "handler defined");
        return (*fun)(std::forward<Args>(args)...);
      }
  
      template <class Type>
      template <class... Args>
      auto variant_functor_impl<Type>::operator()(Args &&... args) const
          -> decltype(std::declval<Type>()(std::forward<Args>(args)...))
      {
        assert(fun && "handler defined");
        return (*fun)(std::forward<Args>(args)...);
      }
  
      template <class Type, class... Types>
      template <class... OtherTypes>
      variant_functor_impl<Type, Types...>::variant_functor_impl(
          char mem[], OtherTypes const &... t)
          : head(mem, t...), tail(mem, t...)
      {
      }
  
      template <class Type, class... Types>
      template <class... OtherTypes>
      variant_functor_impl<Type, Types...>::variant_functor_impl(
          char mem[], variant_functor_impl<OtherTypes...> const &t)
          : head(mem, t), tail(mem, t)
      {
      }
  
      template <class Type, class... Types>
      void variant_functor_impl<Type, Types...>::assign(
          char mem[], variant_functor_impl<Type, Types...> const &other)
      {
        head.assign(mem, other);
        tail.assign(mem, other);
      }
  
      template <class Type, class... Types>
      template <class OtherType>
      void variant_functor_impl<Type, Types...>::assign(char mem[],
                                                        OtherType const &other)
      {
        head.assign(mem, other);
        tail.assign(mem, other);
      }
  
      template <class Type, class... Types>
      template <class... Args>
      auto variant_functor_impl<Type, Types...>::operator()(Args &&... args) ->
          typename __combined<decltype(std::declval<Type>()(args...)),
                              decltype(std::declval<Types>()(args...))...>::type
      {
        if (head.fun)
          return head(args...);
        else
          return tail(args...);
      }
  
      template <class Type, class... Types>
      template <class... Args>
      auto variant_functor_impl<Type, Types...>::operator()(Args &&... args) const
          ->
          typename __combined<decltype(std::declval<Type>()(args...)),
                              decltype(std::declval<Types>()(args...))...>::type
      {
        if (head.fun)
          return head(args...);
        else
          return tail(args...);
      }
    }
  
    template <class... Types>
    variant_functor<Types...>::variant_functor(variant_functor const &other)
        : details::variant_functor_impl<Types...>(
              mem,
              static_cast<details::variant_functor_impl<Types...> const &>(other))
    {
    }
  
    template <class... Types>
    variant_functor<Types...> &variant_functor<Types...>::
    operator=(variant_functor<Types...> const &other)
    {
      details::variant_functor_impl<Types...>::assign(mem, other);
      return *this;
    }
  
    template <class... Types>
    template <class... OtherTypes>
    variant_functor<Types...> &variant_functor<Types...>::
    operator=(variant_functor<OtherTypes...> const &other)
    {
      details::variant_functor_impl<Types...>::assign(mem, other);
      return *this;
    }
  
    template <class... Types>
    template <class OtherType>
    variant_functor<Types...> &variant_functor<Types...>::
    operator=(OtherType const &other)
    {
      static_assert(
          utils::any_of<std::is_same<OtherType, Types>::value...>::value,
          "consistent assign");
      details::variant_functor_impl<Types...>::assign(mem, other);
      return *this;
    }
  
    template <class... Types>
    template <class... OtherTypes>
    variant_functor<Types...>::variant_functor(OtherTypes const &... t)
        : details::variant_functor_impl<Types...>(mem, t...)
    {
    }
  
    template <class... Types>
    template <class... OtherTypes>
    variant_functor<Types...>::variant_functor(
        variant_functor<OtherTypes...> const &t)
        : details::variant_functor_impl<Types...>(
              mem,
              static_cast<details::variant_functor_impl<OtherTypes...> const &>(
                  t))
    {
    }
  }
  PYTHONIC_NS_END
  #endif
  