// bdlb_variant_cpp03.h                                               -*-C++-*-

// Automatically generated file.  **DO NOT EDIT**

#ifndef INCLUDED_BDLB_VARIANT_CPP03
#define INCLUDED_BDLB_VARIANT_CPP03

//@PURPOSE: Provide C++03 implementation for bdlb_variant.h
//
//@CLASSES: See bdlb_variant.h for list of classes
//
//@SEE_ALSO: bdlb_variant
//
//@DESCRIPTION:  This component is the C++03 translation of a C++11 component,
// generated by the 'sim_cpp11_features.pl' program.  If the original header
// contains any specially delimited regions of C++11 code, then this generated
// file contains the C++03 equivalent, i.e., with variadic templates expanded
// and rvalue-references replaced by 'bslmf::MovableRef' objects.  The header
// code in this file is designed to be '#include'd into the original header
// when compiling with a C++03 compiler.  If there are no specially delimited
// regions of C++11 code, then this header contains no code and is not
// '#include'd in the original header.
//
// Generated on Mon Jan 12 21:03:10 2026
// Command line: sim_cpp11_features.pl bdlb_variant.h

#ifdef COMPILING_BDLB_VARIANT_H

#if defined(BSLS_COMPILERFEATURES_SUPPORT_VARIADIC_TEMPLATES) \
 && defined(BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES)
/// Note that this macro definition parallels that of a similar macro
/// defined in `bslmf_typelist.h`.
#define BDLB_VARIANT_USING_VARIADIC_TEMPLATES
#endif

namespace BloombergLP {
namespace bdlb {

struct Variant_CopyAssignVisitor;
struct Variant_CopyConstructVisitor;
struct Variant_DefaultConstructVisitor;
struct Variant_DestructorVisitor;
struct Variant_EqualityTestVisitor;
struct Variant_MoveAssignVisitor;
struct Variant_MoveConstructVisitor;
struct Variant_PrintVisitor;

template <class TYPES>
class VariantImp;

template <class TYPES, class TYPE>
struct Variant_TypeIndex;

                    // ================================
                    // struct Variant_ReturnValueHelper
                    // ================================

// These definitions are provided outside of 'Variant_ReturnValueHelper'
// because of a bug in the IBM xlC compiler.
typedef char                  Variant_ReturnValueHelper_YesType;
typedef struct { char a[2]; } Variant_ReturnValueHelper_NoType;

BSLMF_ASSERT(sizeof(Variant_ReturnValueHelper_YesType)
             != sizeof(Variant_ReturnValueHelper_NoType));

/// This struct is a component-private struct.  Do *not* use.  This provides
/// functions, the matching of which are used by Variant_ReturnValueHelper
/// to determine whether the template parameter type `VISITOR` has the
/// member `ResultType` defined.
struct Variant_ReturnValueHelper_Matcher {

    /// Return `YesType` if `T::ResultType` exists, and `NoType` otherwise.
    /// Note that if `T::ResultType` exists, then the first function is a
    /// better match than the ellipsis version.
    template <class T>
    static Variant_ReturnValueHelper_YesType match(
               typename bsl::remove_reference<typename T::ResultType>::type *);
    template <class T>
    static Variant_ReturnValueHelper_NoType match(...);
};

/// This struct is a component-private meta-function.  Do *not* use.  This
/// meta-function checks whether the template parameter type `VISITOR` has
/// the member `ResultType` defined using "SFINAE" (Substitution Failure Is
/// Not An Error).  A `value` of `true` indicates `VISITOR::ResultType`
/// exists, and `false` otherwise.
template <class VISITOR>
struct Variant_ReturnValueHelper
: public bsl::integral_constant<
      bool,
      sizeof(Variant_ReturnValueHelper_Matcher::match<VISITOR>(0)) ==
          sizeof(Variant_ReturnValueHelper_YesType)> {
};

                   // =====================================
                   // class VariantImp_AllocatorBase<TYPES>
                   // =====================================

/// This class is component-private.  Do not use.  This class contains the
/// `typedef`s and data members of the `Variant` class, and serves as the
/// base class for the variant when any one of the types held by the variant
/// has the `bslma::UsesBslmaAllocator` type trait.
template <class TYPES>
class VariantImp_AllocatorBase {

  public:
    // TYPES

    /// `TypeList` is an alias for the `bslmf::TypeList` type serving as the
    /// template parameter to this variant implementation.
    typedef TYPES TypeList;

    typedef typename bslmf::TypeListTypeOf< 1, TYPES>::TypeOrDefault Type1;
    typedef typename bslmf::TypeListTypeOf< 2, TYPES>::TypeOrDefault Type2;
    typedef typename bslmf::TypeListTypeOf< 3, TYPES>::TypeOrDefault Type3;
    typedef typename bslmf::TypeListTypeOf< 4, TYPES>::TypeOrDefault Type4;
    typedef typename bslmf::TypeListTypeOf< 5, TYPES>::TypeOrDefault Type5;
    typedef typename bslmf::TypeListTypeOf< 6, TYPES>::TypeOrDefault Type6;
    typedef typename bslmf::TypeListTypeOf< 7, TYPES>::TypeOrDefault Type7;
    typedef typename bslmf::TypeListTypeOf< 8, TYPES>::TypeOrDefault Type8;
    typedef typename bslmf::TypeListTypeOf< 9, TYPES>::TypeOrDefault Type9;
    typedef typename bslmf::TypeListTypeOf<10, TYPES>::TypeOrDefault Type10;
    typedef typename bslmf::TypeListTypeOf<11, TYPES>::TypeOrDefault Type11;
    typedef typename bslmf::TypeListTypeOf<12, TYPES>::TypeOrDefault Type12;
    typedef typename bslmf::TypeListTypeOf<13, TYPES>::TypeOrDefault Type13;
    typedef typename bslmf::TypeListTypeOf<14, TYPES>::TypeOrDefault Type14;
    typedef typename bslmf::TypeListTypeOf<15, TYPES>::TypeOrDefault Type15;
    typedef typename bslmf::TypeListTypeOf<16, TYPES>::TypeOrDefault Type16;
    typedef typename bslmf::TypeListTypeOf<17, TYPES>::TypeOrDefault Type17;
    typedef typename bslmf::TypeListTypeOf<18, TYPES>::TypeOrDefault Type18;
    typedef typename bslmf::TypeListTypeOf<19, TYPES>::TypeOrDefault Type19;

    /// `TypeN` is an alias for the `N`th type in the `TypeList` of this
    /// variant implementation.  If less than `N` template arguments were
    /// given to the `Variant` type, then `TypeN` is `bslmf::Nil`.
    typedef typename bslmf::TypeListTypeOf<20, TYPES>::TypeOrDefault Type20;

  private:
    union Value {
        bsls::ObjectBuffer<Type1>  d_v1;
        bsls::ObjectBuffer<Type2>  d_v2;
        bsls::ObjectBuffer<Type3>  d_v3;
        bsls::ObjectBuffer<Type4>  d_v4;
        bsls::ObjectBuffer<Type5>  d_v5;
        bsls::ObjectBuffer<Type6>  d_v6;
        bsls::ObjectBuffer<Type7>  d_v7;
        bsls::ObjectBuffer<Type8>  d_v8;
        bsls::ObjectBuffer<Type9>  d_v9;
        bsls::ObjectBuffer<Type10> d_v10;
        bsls::ObjectBuffer<Type11> d_v11;
        bsls::ObjectBuffer<Type12> d_v12;
        bsls::ObjectBuffer<Type13> d_v13;
        bsls::ObjectBuffer<Type14> d_v14;
        bsls::ObjectBuffer<Type15> d_v15;
        bsls::ObjectBuffer<Type16> d_v16;
        bsls::ObjectBuffer<Type17> d_v17;
        bsls::ObjectBuffer<Type18> d_v18;
        bsls::ObjectBuffer<Type19> d_v19;
        bsls::ObjectBuffer<Type20> d_v20;
    };
        // 'Value' is a union of 'bsls::ObjectBuffer' of all types contained by
        // the variant.  'bsls::ObjectBuffer' is used to: 1) wrap non-POD types
        // within the union, and 2) ensure proper alignment of the types.

    // DATA
    Value             d_value;        // value of the object, initialized by
                                      // derived class

    int               d_type;         // current type the variant is holding (0
                                      // if unset)

    bslma::Allocator *d_allocator_p;  // pointer to allocator (held, not owned)

    // FRIENDS
    template <class VARIANT_TYPES>
    friend class VariantImp;

    template <class VARIANT_TYPES>
    friend bool operator==(const VariantImp<VARIANT_TYPES>&,
                           const VariantImp<VARIANT_TYPES>&);

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(VariantImp_AllocatorBase,
                                   bslma::UsesBslmaAllocator);

    // CREATORS
    VariantImp_AllocatorBase(int type, bslma::Allocator *basicAllocator);

    /// Create a `VariantImp_AllocatorBase` with the specified `type`
    /// indicating the type of the object that the variant will initially
    /// hold, and the specified `basicAllocator` to supply memory.
    VariantImp_AllocatorBase(int               type,
                             bslma::Allocator *basicAllocator,
                             bsl::true_type);

    template <class TYPE>
    VariantImp_AllocatorBase(int type, const TYPE&, bsl::false_type);

    // ACCESSORS

    /// Return the allocator used by this object to supply memory.
    bslma::Allocator *getAllocator() const;
};

                  // =======================================
                  // class VariantImp_NoAllocatorBase<TYPES>
                  // =======================================

/// This class is component-private.  Do not use.  This class contains the
/// `typedef`s and data members of the `Variant` class, and serves as the
/// base class for the variant when none of the types held by the variant
/// has the `bslma::UsesBslmaAllocator` type trait.  The goal is to optimize
/// the size of the variant to avoid holding an unnecessary allocator
/// pointer.
template <class TYPES>
class VariantImp_NoAllocatorBase {

  public:
    // TYPES

    /// `TypeList` is an alias for the `bslmf::TypeList` type serving as the
    /// template parameter to this variant implementation.
    typedef TYPES TypeList;

    typedef typename bslmf::TypeListTypeOf< 1, TYPES>::TypeOrDefault Type1;
    typedef typename bslmf::TypeListTypeOf< 2, TYPES>::TypeOrDefault Type2;
    typedef typename bslmf::TypeListTypeOf< 3, TYPES>::TypeOrDefault Type3;
    typedef typename bslmf::TypeListTypeOf< 4, TYPES>::TypeOrDefault Type4;
    typedef typename bslmf::TypeListTypeOf< 5, TYPES>::TypeOrDefault Type5;
    typedef typename bslmf::TypeListTypeOf< 6, TYPES>::TypeOrDefault Type6;
    typedef typename bslmf::TypeListTypeOf< 7, TYPES>::TypeOrDefault Type7;
    typedef typename bslmf::TypeListTypeOf< 8, TYPES>::TypeOrDefault Type8;
    typedef typename bslmf::TypeListTypeOf< 9, TYPES>::TypeOrDefault Type9;
    typedef typename bslmf::TypeListTypeOf<10, TYPES>::TypeOrDefault Type10;
    typedef typename bslmf::TypeListTypeOf<11, TYPES>::TypeOrDefault Type11;
    typedef typename bslmf::TypeListTypeOf<12, TYPES>::TypeOrDefault Type12;
    typedef typename bslmf::TypeListTypeOf<13, TYPES>::TypeOrDefault Type13;
    typedef typename bslmf::TypeListTypeOf<14, TYPES>::TypeOrDefault Type14;
    typedef typename bslmf::TypeListTypeOf<15, TYPES>::TypeOrDefault Type15;
    typedef typename bslmf::TypeListTypeOf<16, TYPES>::TypeOrDefault Type16;
    typedef typename bslmf::TypeListTypeOf<17, TYPES>::TypeOrDefault Type17;
    typedef typename bslmf::TypeListTypeOf<18, TYPES>::TypeOrDefault Type18;
    typedef typename bslmf::TypeListTypeOf<19, TYPES>::TypeOrDefault Type19;

    /// `TypeN` is an alias for the `N`th type in the `TypeList` of this
    /// variant implementation.  If less than `N` template arguments were
    /// given to the `Variant` type, then `TypeN` is `bslmf::Nil`.
    typedef typename bslmf::TypeListTypeOf<20, TYPES>::TypeOrDefault Type20;

  private:
    union Value {
        bsls::ObjectBuffer<Type1>  d_v1;
        bsls::ObjectBuffer<Type2>  d_v2;
        bsls::ObjectBuffer<Type3>  d_v3;
        bsls::ObjectBuffer<Type4>  d_v4;
        bsls::ObjectBuffer<Type5>  d_v5;
        bsls::ObjectBuffer<Type6>  d_v6;
        bsls::ObjectBuffer<Type7>  d_v7;
        bsls::ObjectBuffer<Type8>  d_v8;
        bsls::ObjectBuffer<Type9>  d_v9;
        bsls::ObjectBuffer<Type10> d_v10;
        bsls::ObjectBuffer<Type11> d_v11;
        bsls::ObjectBuffer<Type12> d_v12;
        bsls::ObjectBuffer<Type13> d_v13;
        bsls::ObjectBuffer<Type14> d_v14;
        bsls::ObjectBuffer<Type15> d_v15;
        bsls::ObjectBuffer<Type16> d_v16;
        bsls::ObjectBuffer<Type17> d_v17;
        bsls::ObjectBuffer<Type18> d_v18;
        bsls::ObjectBuffer<Type19> d_v19;
        bsls::ObjectBuffer<Type20> d_v20;
    };
        // 'Value' is a union of 'bsls::ObjectBuffer' of all types contained by
        // the variant.  'bsls::ObjectBuffer' is used to: 1) wrap non-POD types
        // within the union, and 2) ensure proper alignment of the types.

    // DATA
    Value d_value;  // value of the object, initialized by derived class
    int   d_type;   // current type the variant is holding (0 if unset)

    // FRIENDS
    template <class VARIANT_TYPES>
    friend class VariantImp;

    template <class VARIANT_TYPES>
    friend bool operator==(const VariantImp<VARIANT_TYPES>&,
                           const VariantImp<VARIANT_TYPES>&);

  public:
    // CREATORS
    VariantImp_NoAllocatorBase(int type, bslma::Allocator *);

    /// Create a `VariantImp_NoAllocatorBase` with the specified `type`
    /// indicating the type of the object that the variant will initially
    /// hold.
    VariantImp_NoAllocatorBase(int type, bslma::Allocator *, bsl::true_type);

    template <class TYPE>
    VariantImp_NoAllocatorBase(int type, const TYPE&, bsl::false_type);

    // ACCESSORS

    /// Return 0.  Note that this object does not hold an allocator pointer.
    bslma::Allocator *getAllocator() const;
};

                       // ========================
                       // struct VariantImp_Traits
                       // ========================

/// This struct is component-private.  Do not use.  This meta-function
/// selects `VariantImp_AllocatorBase` as a base class type if any one of
/// the types held by a variant has the `bslma::UsesBslmaAllocator` trait,
/// and `VariantImp_NoAllocatorBase` otherwise.
template <class TYPES>
struct VariantImp_Traits {

    // TYPES
    typedef typename bslmf::TypeListTypeOf< 1, TYPES>::TypeOrDefault Type1;
    typedef typename bslmf::TypeListTypeOf< 2, TYPES>::TypeOrDefault Type2;
    typedef typename bslmf::TypeListTypeOf< 3, TYPES>::TypeOrDefault Type3;
    typedef typename bslmf::TypeListTypeOf< 4, TYPES>::TypeOrDefault Type4;
    typedef typename bslmf::TypeListTypeOf< 5, TYPES>::TypeOrDefault Type5;
    typedef typename bslmf::TypeListTypeOf< 6, TYPES>::TypeOrDefault Type6;
    typedef typename bslmf::TypeListTypeOf< 7, TYPES>::TypeOrDefault Type7;
    typedef typename bslmf::TypeListTypeOf< 8, TYPES>::TypeOrDefault Type8;
    typedef typename bslmf::TypeListTypeOf< 9, TYPES>::TypeOrDefault Type9;
    typedef typename bslmf::TypeListTypeOf<10, TYPES>::TypeOrDefault Type10;
    typedef typename bslmf::TypeListTypeOf<11, TYPES>::TypeOrDefault Type11;
    typedef typename bslmf::TypeListTypeOf<12, TYPES>::TypeOrDefault Type12;
    typedef typename bslmf::TypeListTypeOf<13, TYPES>::TypeOrDefault Type13;
    typedef typename bslmf::TypeListTypeOf<14, TYPES>::TypeOrDefault Type14;
    typedef typename bslmf::TypeListTypeOf<15, TYPES>::TypeOrDefault Type15;
    typedef typename bslmf::TypeListTypeOf<16, TYPES>::TypeOrDefault Type16;
    typedef typename bslmf::TypeListTypeOf<17, TYPES>::TypeOrDefault Type17;
    typedef typename bslmf::TypeListTypeOf<18, TYPES>::TypeOrDefault Type18;
    typedef typename bslmf::TypeListTypeOf<19, TYPES>::TypeOrDefault Type19;
    typedef typename bslmf::TypeListTypeOf<20, TYPES>::TypeOrDefault Type20;

    enum {
        k_VARIANT_USES_BSLMA_ALLOCATOR = (
            bslma::UsesBslmaAllocator< Type1>::value
         || bslma::UsesBslmaAllocator< Type2>::value
         || bslma::UsesBslmaAllocator< Type3>::value
         || bslma::UsesBslmaAllocator< Type4>::value
         || bslma::UsesBslmaAllocator< Type5>::value
         || bslma::UsesBslmaAllocator< Type6>::value
         || bslma::UsesBslmaAllocator< Type7>::value
         || bslma::UsesBslmaAllocator< Type8>::value
         || bslma::UsesBslmaAllocator< Type9>::value
         || bslma::UsesBslmaAllocator<Type10>::value
         || bslma::UsesBslmaAllocator<Type11>::value
         || bslma::UsesBslmaAllocator<Type12>::value
         || bslma::UsesBslmaAllocator<Type13>::value
         || bslma::UsesBslmaAllocator<Type14>::value
         || bslma::UsesBslmaAllocator<Type15>::value
         || bslma::UsesBslmaAllocator<Type16>::value
         || bslma::UsesBslmaAllocator<Type17>::value
         || bslma::UsesBslmaAllocator<Type18>::value
         || bslma::UsesBslmaAllocator<Type19>::value
         || bslma::UsesBslmaAllocator<Type20>::value),

        k_VARIANT_IS_BITWISE_COPYABLE = (
            bslmf::IsBitwiseCopyable< Type1>::value
         && bslmf::IsBitwiseCopyable< Type2>::value
         && bslmf::IsBitwiseCopyable< Type3>::value
         && bslmf::IsBitwiseCopyable< Type4>::value
         && bslmf::IsBitwiseCopyable< Type5>::value
         && bslmf::IsBitwiseCopyable< Type6>::value
         && bslmf::IsBitwiseCopyable< Type7>::value
         && bslmf::IsBitwiseCopyable< Type8>::value
         && bslmf::IsBitwiseCopyable< Type9>::value
         && bslmf::IsBitwiseCopyable<Type10>::value
         && bslmf::IsBitwiseCopyable<Type11>::value
         && bslmf::IsBitwiseCopyable<Type12>::value
         && bslmf::IsBitwiseCopyable<Type13>::value
         && bslmf::IsBitwiseCopyable<Type14>::value
         && bslmf::IsBitwiseCopyable<Type15>::value
         && bslmf::IsBitwiseCopyable<Type16>::value
         && bslmf::IsBitwiseCopyable<Type17>::value
         && bslmf::IsBitwiseCopyable<Type18>::value
         && bslmf::IsBitwiseCopyable<Type19>::value
         && bslmf::IsBitwiseCopyable<Type20>::value),

        k_VARIANT_IS_BITWISE_MOVEABLE = (
            bslmf::IsBitwiseMoveable< Type1>::value
         && bslmf::IsBitwiseMoveable< Type2>::value
         && bslmf::IsBitwiseMoveable< Type3>::value
         && bslmf::IsBitwiseMoveable< Type4>::value
         && bslmf::IsBitwiseMoveable< Type5>::value
         && bslmf::IsBitwiseMoveable< Type6>::value
         && bslmf::IsBitwiseMoveable< Type7>::value
         && bslmf::IsBitwiseMoveable< Type8>::value
         && bslmf::IsBitwiseMoveable< Type9>::value
         && bslmf::IsBitwiseMoveable<Type10>::value
         && bslmf::IsBitwiseMoveable<Type11>::value
         && bslmf::IsBitwiseMoveable<Type12>::value
         && bslmf::IsBitwiseMoveable<Type13>::value
         && bslmf::IsBitwiseMoveable<Type14>::value
         && bslmf::IsBitwiseMoveable<Type15>::value
         && bslmf::IsBitwiseMoveable<Type16>::value
         && bslmf::IsBitwiseMoveable<Type17>::value
         && bslmf::IsBitwiseMoveable<Type18>::value
         && bslmf::IsBitwiseMoveable<Type19>::value
         && bslmf::IsBitwiseMoveable<Type20>::value)
#ifndef BDE_OMIT_INTERNAL_DEPRECATED
      , VARIANT_USES_BSLMA_ALLOCATOR = k_VARIANT_USES_BSLMA_ALLOCATOR
      , VARIANT_IS_BITWISE_COPYABLE  = k_VARIANT_IS_BITWISE_COPYABLE
      , VARIANT_IS_BITWISE_MOVEABLE  = k_VARIANT_IS_BITWISE_MOVEABLE
#endif  // BDE_OMIT_INTERNAL_DEPRECATED
    };

    /// Determines what the base type is.
    typedef typename bsl::conditional<k_VARIANT_USES_BSLMA_ALLOCATOR,
                                      VariantImp_AllocatorBase<TYPES>,
                                      VariantImp_NoAllocatorBase<TYPES> >::type
                                                                      BaseType;
};

                       // ==============================
                       // class Variant_RawVisitorHelper
                       // ==============================

/// This `struct` provides a helper for implementing `Variant::applyRaw`
/// that enables `applyRaw` to support visitor functors that do not provide
/// an overload for `operator()(bslmf::Nil)`.  Objects of this type are
/// constructed using a functor of (template parameter) type `VISITOR`,
/// whose `operator()` returns the (template parameter) type `RESULT_TYPE`.
/// A `Variant_RawVisitorHelper` wraps a functor of type `VISITOR` and
/// provides an implementation of `operator()(bslmf::Nil)` that performs a
/// `BSLS_ASSERT_OPT(false)`.  Note that this overload is needed to enable
/// compilation (specifically, to instantiate `doApply` and `doApplyR`), but
/// is never invoked by any code path at runtime.
template <class RESULT_TYPE, class VISITOR>
class Variant_RawVisitorHelper {

    // DATA
    VISITOR *d_visitor;  // visitor to which this helper delegates

  public:
    // CREATORS

    /// Create a `RawVisitorHelper` functor that delegates to the specified
    /// `visitor`.
    explicit
    Variant_RawVisitorHelper(VISITOR *visitor);

    // MANIPULATORS

    /// Invoke the functor supplied at construction with the specified
    /// `argument`, and return the result.
    template <class ARGUMENT_TYPE>
    RESULT_TYPE operator()(ARGUMENT_TYPE& argument);
    template <class ARGUMENT_TYPE>
    RESULT_TYPE operator()(const ARGUMENT_TYPE& argument);

    // ACCESSORS

    /// Invoke the functor supplied at construction with the specified
    /// `argument`, and return the result.
    template <class ARGUMENT_TYPE>
    RESULT_TYPE operator()(ARGUMENT_TYPE& argument) const;
    template <class ARGUMENT_TYPE>
    RESULT_TYPE operator()(const ARGUMENT_TYPE& argument) const;

    /// Do not call.  The behavior of this method is undefined.
    RESULT_TYPE operator()(bslmf::Nil) const;
};

                       // =======================
                       // class VariantImp<TYPES>
                       // =======================

/// This class provides the implementation of `Variant` (except for the
/// creators) given a list of template parameter `TYPES`.
///
/// More generally, if each of the types in the list of `TYPES` is
/// value semantic, then this class also supports a complete set of *value*
/// *semantic* operations, including copy construction, assignment, equality
/// comparison, and `ostream` printing.  A precise operational definition of
/// when two instances have the same value can be found in the description
/// of `operator==` for the class.  This class is *exception* *neutral* with
/// no guarantee of rollback: if an exception is thrown during the
/// invocation of a method on a pre-existing instance, the object is left in
/// a valid state, but its value is undefined.  In no event is memory
/// leaked.  Finally, *aliasing* (e.g., using all or part of an object as
/// both source and destination) is supported in all cases.
///
/// If any of the types in the list of `TYPES` does not support
/// `operator==`, or any of the value-semantic operations mentioned above,
/// then this variant also does not support that operation and attempts to
/// invoke it will trigger a compilation diagnostic.
template <class TYPES>
class VariantImp : public VariantImp_Traits<TYPES>::BaseType {

    // PRIVATE TYPES
    typedef VariantImp_Traits<TYPES>  Traits;
    typedef typename Traits::BaseType Base;
    typedef bslmf::MovableRefUtil     MoveUtil;

    /// `SelfType` is an alias to this class.
    typedef VariantImp<TYPES>         SelfType;

  private:
    // PRIVATE MANIPULATORS

    /// Invoke `operator()` of the specified `visitor` on the current value
    /// (of template parameter `TYPE`) held by this variant.  `TYPE` must be
    /// the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless this variant holds a value of template
    /// parameter `TYPE`.  Note that the second argument is for resolving
    /// overloading ambiguity and is not used.
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor, bsl::false_type);
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor, bsl::true_type);
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor);

    /// Invoke `operator()` of the specified `visitor` on the current value
    /// (of template parameter `TYPE`) held by this variant, and return the
    /// value (of template parameter `RET_TYPE`) returned by the `visitor`.
    /// `TYPE` must be the same as one of the types that this variant can
    /// hold.  The behavior is undefined unless this variant holds a value
    /// of template parameter `TYPE`.  Note that the second argument is for
    /// resolving overloading ambiguity and is not used.
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor, bsl::false_type);
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor, bsl::true_type);
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor);

    /// Assign to this variant the specified `value` of template parameter
    /// `SOURCE_TYPE` converted to template parameter `TYPE`.  `TYPE` must
    /// be the same as one of the types that this variant can hold and
    /// `SOURCE_TYPE` must be convertible to `TYPE`.
    template <class TYPE, class SOURCE_TYPE>
    void assignImp(const SOURCE_TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    void assignImp(TYPE&&                  value);
#else
    void assignImp(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this variant the specified 'value' of template parameter
        // 'TYPE'.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  'TYPE' must be the
        // same as one of the types that this variant can hold.

    /// Construct this variant object to initially hold the specified
    /// `value` of template parameter `TYPE`.  `TYPE` must be the same as
    /// one of the types that this variant can hold.  Note that the second
    /// parameter is for resolving overloading ambiguity and is not used.
    template <class TYPE>
    void create(const TYPE& value, bsl::false_type);

    /// Construct this variant object to be initially in the unset state.
    void create(bslma::Allocator *, bsl::true_type);

    /// Apply the specified `visitor` on the current value held by this
    /// variant by invoking `applyImp` with the appropriate template
    /// arguments, determined by the specified `type`.  The behavior is
    /// undefined unless `type != 0`.
    template <class VISITOR_REF>
    void doApply(VISITOR_REF visitor, int type);

    /// Apply the specified `visitor` on the current value held by this
    /// variant by invoking `applyImpR` with the appropriate template
    /// arguments, determined by the specified `type`, and return the value
    /// (of template parameter `RET_TYPE`) returned by the `visitor`.  The
    /// behavior is undefined unless `type != 0`.
    template <class VISITOR_REF, class RET_TYPE>
    RET_TYPE doApplyR(VISITOR_REF visitor, int type);

    // PRIVATE ACCESSORS

    /// Invoke `operator()` of the specified `visitor` on the current value
    /// (of template parameter `TYPE`) held by this variant.  `TYPE` must be
    /// the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless this variant holds a value of template
    /// parameter `TYPE`.  Note that the second argument is for resolving
    /// overloading ambiguity and is not used.
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor, bsl::false_type) const;
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor, bsl::true_type) const;
    template <class TYPE, class VISITOR_REF>
    void applyImp(VISITOR_REF visitor) const;

    /// Invoke `operator()` of the specified `visitor` on the current value
    /// (of template parameter `TYPE`) held by this variant, and return the
    /// value (of template parameter `RET_TYPE`) returned by the `visitor`.
    /// `TYPE` must be the same as one of the types that this variant can
    /// hold.  The behavior is undefined unless this variant holds a value
    /// of template parameter `TYPE`.  Note that the second argument is for
    /// resolving overloading ambiguity and is not used.
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor, bsl::false_type) const;
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor, bsl::true_type) const;
    template <class TYPE, class VISITOR_REF, class RET_TYPE>
    RET_TYPE applyImpR(VISITOR_REF visitor) const;

    /// Apply the specified `visitor` on the current value held by this
    /// variant by invoking `applyImp` with the appropriate template
    /// arguments, determined by the specified `type`.  The behavior is
    /// undefined unless `type != 0`.
    template <class VISITOR_REF>
    void doApply(VISITOR_REF visitor, int type) const;

    /// Apply the specified `visitor` on the current value held by this
    /// variant by invoking `applyImpR` with the appropriate template
    /// arguments, determined by the specified `type`, and return the value
    /// (of template parameter `RET_TYPE`) returned by the `visitor`.  The
    /// behavior is undefined unless `type != 0`.
    template <class VISITOR_REF, class RET_TYPE>
    RET_TYPE doApplyR(VISITOR_REF visitor, int type) const;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(VariantImp,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(VariantImp,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(VariantImp,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(VariantImp, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    VariantImp();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    VariantImp(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    VariantImp(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    VariantImp(TYPE&&                   value,
               typename bsl::enable_if<
                   !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                   &&
                   !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                           void>::type * = 0);
#else
    VariantImp(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    VariantImp(TYPE&&                   value,
               typename bsl::enable_if<
                   !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
               bslma::Allocator>::type *basicAllocator);
#else
    VariantImp(bslmf::MovableRef<TYPE>  value,
               bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    VariantImp(const VariantImp&  original,
               bslma::Allocator  *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    VariantImp(bslmf::MovableRef<VariantImp> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    VariantImp(bslmf::MovableRef<VariantImp>  original,
               bslma::Allocator              *basicAllocator);

    /// Destroy this variant object, invoking the destructor of the type of
    /// object contained (if any) on the value of that type.
    ~VariantImp();

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    VariantImp& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    VariantImp&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    VariantImp& operator=(const VariantImp& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    VariantImp& operator=(bslmf::MovableRef<VariantImp> rhs);

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value this variant currently holds to the `visitor` object's
    /// `operator()`, and return the value returned by the `visitor`.  If
    /// this variant is unset, a default constructed `bslmf::Nil` is passed
    /// to the `visitor`.  Note that this method is selected only if the
    /// template parameter type `VISITOR` defines a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(VISITOR& visitor) {

        if (this->d_type) {
            return doApplyR<VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        return visitor(nil);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value this variant currently holds to the `visitor` object's
    /// `operator()`, and return the value returned by the `visitor`.  If
    /// If this variant is unset, a default constructed `bslmf::Nil` is
    /// passed to the `visitor`.  Note that this method is selected only if
    /// the template parameter type `VISITOR` defines a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(const VISITOR& visitor) {

        if (this->d_type) {
            return doApplyR<const VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        return visitor(nil);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// returned by the `visitor`.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// defines a `typedef` of `ResultType` in its public interface.  Also
    /// note that this method is defined inline to work around a Windows
    /// compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(VISITOR& visitor, const TYPE& defaultValue) {

        if (this->d_type) {
            return doApplyR<VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        return visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// returned by the `visitor`.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// defines a `typedef` of `ResultType` in its public interface.  Also
    /// note that this method is defined inline to work around a Windows
    /// compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(const VISITOR& visitor, const TYPE& defaultValue) {

        if (this->d_type) {
            return doApplyR<const VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        return visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value this variant currently holds to the `visitor` object's
    /// `operator()`.  This method does not return a value.  If this variant
    /// is unset, a default constructed `bslmf::Nil` is passed to the
    /// `visitor`.  Note that this method is selected only if the template
    /// parameter type `VISITOR` does not define a `typedef` of `ResultType`
    /// in its public interface.  Also note that this method is defined
    /// inline to work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(VISITOR& visitor) {

        if (this->d_type) {
            doApply<VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        visitor(nil);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value this variant currently holds to the `visitor` object's
    /// `operator()`.  This method does not return a value.  If this variant
    /// is unset, a default constructed `bslmf::Nil` is passed to the
    /// `visitor`.  Note that this method is selected only if the template
    /// parameter type `VISITOR` does not define a `typedef` of `ResultType`
    /// in its public interface.  Also note that this method is defined
    /// inline to work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(const VISITOR& visitor) {

        if (this->d_type) {
            doApply<const VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        visitor(nil);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`.  This method does not
    /// return a value.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// does not define a `typedef` of `ResultType` in its public interface.
    /// Also note that this method is defined inline to work around a
    /// Windows compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(VISITOR& visitor, const TYPE& defaultValue) {

        if (this->d_type) {
            doApply<VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`.  This method does not
    /// return a value.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// does not define a `typedef` of `ResultType` in its public interface.
    /// Also note that this method is defined inline to work around a
    /// Windows compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(const VISITOR& visitor, const TYPE& defaultValue) {

        if (this->d_type) {
            doApply<const VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// (of template parameter `RET_TYPE`) returned by the `visitor`.  If
    /// this variant is unset, a default constructed `bslmf::Nil` is passed
    /// to the `visitor`.
    template <class RET_TYPE, class VISITOR>
    RET_TYPE apply(VISITOR& visitor);
    template <class RET_TYPE, class VISITOR>
    RET_TYPE apply(const VISITOR& visitor);

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// (of template parameter `RET_TYPE`) returned by the `visitor`.  If
    /// this variant is unset, the specified `defaultValue` of template
    /// parameter `TYPE` is passed to the `visitor`.  `TYPE` must be the
    /// same as one of the types that this variant can hold.  The behavior
    /// is undefined unless this variant is unset or holds a value of
    /// template parameter `TYPE`.
    template <class RET_TYPE, class VISITOR, class TYPE>
    RET_TYPE apply(VISITOR& visitor, const TYPE& defaultValue);
    template <class RET_TYPE, class VISITOR, class TYPE>
    RET_TYPE apply(const VISITOR& visitor, const TYPE& defaultValue);

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// returned by the `visitor`.  The behavior is undefined if this
    /// variant is unset.  Note that this method is selected only if the
    /// template parameter type `VISITOR` defines a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    applyRaw(VISITOR& visitor) {

        typedef Variant_RawVisitorHelper<typename VISITOR::ResultType,
                                         VISITOR> Helper;

        return doApplyR<const Helper&,
                        typename VISITOR::ResultType>(Helper(&visitor),
                                                      this->d_type);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`, and return the value
    /// returned by the `visitor`.  The behavior is undefined if this
    /// variant is unset.  Note that this method is selected only if the
    /// template parameter type `VISITOR` defines a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    applyRaw(const VISITOR& visitor) {

        typedef Variant_RawVisitorHelper<typename VISITOR::ResultType,
                                         const VISITOR> Helper;

        return doApplyR<const Helper&,
                        typename VISITOR::ResultType>(Helper(&visitor),
                                                      this->d_type);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`.  This method does not
    /// return a value.  The behavior is undefined if this variant is unset.
    /// Note that this method is selected only if the template parameter
    /// type `VISITOR` does not define a `typedef` of `ResultType` in its
    /// public interface.  Also note that this method is defined inline to
    /// work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    applyRaw(VISITOR& visitor) {

        typedef Variant_RawVisitorHelper<void, VISITOR> Helper;

        doApply<const Helper&>(Helper(&visitor), this->d_type);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value (of template parameter `TYPE`) this variant currently
    /// holds to the `visitor` object's `operator()`.  This method does not
    /// return a value.  The behavior is undefined if this variant is unset.
    /// Note that this method is selected only if the template parameter
    /// type `VISITOR` does not define a `typedef` of `ResultType` in its
    /// public interface.  Also note that this method is defined inline to
    /// work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    applyRaw(const VISITOR& visitor) {

        typedef Variant_RawVisitorHelper<void, const VISITOR> Helper;

        doApply<const Helper&>(Helper(&visitor), this->d_type);
    }

    /// Apply the specified `visitor` to this modifiable variant by passing
    /// the value this variant currently holds to the `visitor` object's
    /// `operator()`, and return the value (of template parameter
    /// `RET_TYPE`) returned by the `visitor`.  The behavior is undefined if
    /// this variant is unset.
    template <class RET_TYPE, class VISITOR>
    RET_TYPE applyRaw(VISITOR& visitor);
    template <class RET_TYPE, class VISITOR>
    RET_TYPE applyRaw(const VISITOR& visitor);

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    VariantImp& assign(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    VariantImp& assign(TYPE&&                  value);
#else
    VariantImp& assign(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.

    /// Assign to this object the specified `value` of template parameter
    /// `SOURCE_TYPE` converted to template parameter `TYPE`, and return a
    /// reference providing modifiable access to this object.  The value
    /// currently held by this variant (if any) is destroyed if that value's
    /// type is not the same as `TYPE`.  `TYPE` must be the same as one of
    /// the types that this variant can hold and `SOURCE_TYPE` must be
    /// convertible to `TYPE`.
    template <class TYPE, class SOURCE_TYPE>
    VariantImp& assignTo(const SOURCE_TYPE& value);

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_variant.h
#ifndef BDLB_VARIANT_VARIADIC_LIMIT
#define BDLB_VARIANT_VARIADIC_LIMIT 14
#endif
#ifndef BDLB_VARIANT_VARIADIC_LIMIT_A
#define BDLB_VARIANT_VARIADIC_LIMIT_A BDLB_VARIANT_VARIADIC_LIMIT
#endif

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 0
    template <class TYPE>
    TYPE& createInPlace();
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 0

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 1
    template <class TYPE, class ARGS_01>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 1

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 2
    template <class TYPE, class ARGS_01,
                          class ARGS_02>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 2

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 3
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 3

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 4
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 4

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 5
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 5

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 6
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 6

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 7
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 7

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 8
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 8

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 9
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 9

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 10
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09,
                          class ARGS_10>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 10

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 11
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09,
                          class ARGS_10,
                          class ARGS_11>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 11

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 12
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09,
                          class ARGS_10,
                          class ARGS_11,
                          class ARGS_12>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 12

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 13
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09,
                          class ARGS_10,
                          class ARGS_11,
                          class ARGS_12,
                          class ARGS_13>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_13) arguments_13);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 13

#if BDLB_VARIANT_VARIADIC_LIMIT_A >= 14
    template <class TYPE, class ARGS_01,
                          class ARGS_02,
                          class ARGS_03,
                          class ARGS_04,
                          class ARGS_05,
                          class ARGS_06,
                          class ARGS_07,
                          class ARGS_08,
                          class ARGS_09,
                          class ARGS_10,
                          class ARGS_11,
                          class ARGS_12,
                          class ARGS_13,
                          class ARGS_14>
    TYPE& createInPlace(
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_13) arguments_13,
                      BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_14) arguments_14);
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_A >= 14

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.

    template <class TYPE, class... ARGS>
    TYPE& createInPlace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)... arguments);
// }}} END GENERATED CODE
#endif

    /// Destroy the current value held by this variant (if any), and reset
    /// this variant to the unset state.
    void reset();

    /// Swap the value of this object with the value of the specified
    /// `other` object.  This method provides the no-throw guarantee if the
    /// `TYPE` template parameter has a no-throw `swap` and the two variant
    /// objects being swapped have the same type; otherwise this method
    /// provides the basic guarantee.
    void swap(VariantImp& other);

    /// Return a reference providing modifiable access to the value of
    /// template parameter `TYPE` held by this variant object.  `TYPE` must
    /// be the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless `is<TYPE>()` returns `true` and `TYPE`
    /// is not `void`.  Note that `TYPE` must be specified explicitly, e.g.,
    /// `myValue.the<int>()`.
    template <class TYPE>
    TYPE& the();

    // ACCESSORS

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value returned by the `visitor`.  If this variant is
    /// unset, a default constructed `bslmf::Nil` is passed to the
    /// `visitor`.  Note that this method is selected only if the template
    /// parameter type `VISITOR` defines a `typedef` of `ResultType` in its
    /// public interface.  Also note that this method is defined inline to
    /// work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(VISITOR& visitor) const {

        if (this->d_type) {
            return doApplyR<VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        return visitor(nil);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value returned by the 'visitor.  If this variant is
    /// unset, a default constructed `bslmf::Nil` is passed to the
    /// `visitor`.  Note that this method is selected only if the template
    /// parameter type `VISITOR` defines a `typedef` of `ResultType` in its
    /// public interface.  Also note that this method is defined inline to
    /// work around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(const VISITOR& visitor) const {

        if (this->d_type) {
            return doApplyR<const VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        return visitor(nil);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// (of template parameter `TYPE`) this variant currently holds to the
    /// `visitor` object's `operator()`, and return the value returned by
    /// the `visitor`.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// defines a `typedef` of `ResultType` in its public interface.  Also
    /// note that this method is defined inline to work around a Windows
    /// compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(VISITOR& visitor, const TYPE& defaultValue) const {

        if (this->d_type) {
            return doApplyR<VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        return visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// (of template parameter `TYPE`) this variant currently holds to the
    /// `visitor` object's `operator()`, and return the value returned by
    /// the `visitor`.  If this variant is unset, the specified
    /// `defaultValue` of template parameter `TYPE` is passed to the
    /// `visitor`.  `TYPE` must be the same as one of the types that this
    /// variant can hold.  The behavior is undefined unless this variant is
    /// unset or holds a value of template parameter `TYPE`.  Note that this
    /// method is selected only if the template parameter type `VISITOR`
    /// defines a `typedef` of `ResultType` in its public interface.  Also
    /// note that this method is defined inline to work around a Windows
    /// compiler bug with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    apply(const VISITOR& visitor, const TYPE& defaultValue) const {

        if (this->d_type) {
            return doApplyR<const VISITOR&,
                          typename VISITOR::ResultType>(visitor, this->d_type);
                                                                      // RETURN
        }

        return visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`.
    /// This method does not return a value.  If this variant is unset, a
    /// default constructed `bslmf::Nil` is passed to the `visitor`.  Note
    /// that this method is selected only if the template parameter type
    /// `VISITOR` does not define a `typedef` of `ResultType` in its public
    /// interface.  Also note that this method is defined inline to work
    /// around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(VISITOR& visitor) const {

        if (this->d_type) {
            doApply<VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        visitor(nil);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`.
    /// This method does not return a value.  If this variant is unset, a
    /// default constructed `bslmf::Nil` is passed to the `visitor`.  Note
    /// that this method is selected only if the template parameter type
    /// `VISITOR` does not define a `typedef` of `ResultType` in its public
    /// interface.  Also note that this method is defined inline to work
    /// around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(const VISITOR& visitor) const {

        if (this->d_type) {
            doApply<const VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        bslmf::Nil nil = bslmf::Nil();
        visitor(nil);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// (of template parameter `TYPE`) this variant currently holds to the
    /// `visitor` object's `operator()`.  This method does not return a
    /// value.  If this variant is unset, the specified `defaultValue` of
    /// template parameter `TYPE` is passed to the `visitor`.  `TYPE` must
    /// be the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless this variant is unset or holds a value
    /// of template parameter `TYPE`.  Note that this method is selected
    /// only if the template parameter type `VISITOR` does not define a
    /// `typedef` of `ResultType` in its public interface.  Also note that
    /// this method is defined inline to work around a Windows compiler bug
    /// with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(VISITOR& visitor, const TYPE& defaultValue) const {

        if (this->d_type) {
            doApply<VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// (of template parameter `TYPE`) this variant currently holds to the
    /// `visitor` object's `operator()`.  This method does not return a
    /// value.  If this variant is unset, the specified `defaultValue` of
    /// template parameter `TYPE` is passed to the `visitor`.  `TYPE` must
    /// be the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless this variant is unset or holds a value
    /// of template parameter `TYPE`.  Note that this method is selected
    /// only if the template parameter type `VISITOR` does not define a
    /// `typedef` of `ResultType` in its public interface.  Also note that
    /// this method is defined inline to work around a Windows compiler bug
    /// with SFINAE functions.
    template <class VISITOR, class TYPE>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    apply(const VISITOR& visitor, const TYPE& defaultValue) const {

        if (this->d_type) {
            doApply<const VISITOR&>(visitor, this->d_type);
            return;                                                   // RETURN
        }

        visitor(defaultValue);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value (of template parameter `RET_TYPE`) returned by
    /// the `visitor`.  If this variant is unset, a default constructed
    /// `bslmf::Nil` is passed to the `visitor`.
    template <class RET_TYPE, class VISITOR>
    RET_TYPE apply(VISITOR& visitor) const;
    template <class RET_TYPE, class VISITOR>
    RET_TYPE apply(const VISITOR& visitor) const;

    /// Apply the specified `visitor` to this variant by passing the value
    /// (of template parameter `TYPE`) this variant currently holds to the
    /// `visitor` object's `operator()`, and return the value (of template
    /// parameter `RET_TYPE`) returned by the `visitor`.  If this variant is
    /// unset, the specified `defaultValue` of template parameter `TYPE` is
    /// passed to the `visitor`.  `TYPE` must be the same as one of the
    /// types that this variant can hold.  The behavior is undefined unless
    /// this variant is unset or holds a value of template parameter `TYPE`.
    template <class RET_TYPE, class VISITOR, class TYPE>
    RET_TYPE apply(VISITOR& visitor, const TYPE& defaultValue) const;
    template <class RET_TYPE, class VISITOR, class TYPE>
    RET_TYPE apply(const VISITOR& visitor, const TYPE& defaultValue) const;

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value (of template parameter `RET_TYPE`) returned by
    /// the `visitor`.  The behavior is undefined if this variant is unset.
    /// Note that this method is selected only if the template parameter
    /// type `VISITOR` defines a `typedef` of `ResultType` in its public
    /// interface.  Also note that this method is defined inline to work
    /// around a Windows compiler bug with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    applyRaw(VISITOR& visitor) const {

        typedef Variant_RawVisitorHelper<typename VISITOR::ResultType,
                                         VISITOR> Helper;

        return doApplyR<const Helper&,
                        typename VISITOR::ResultType>(Helper(&visitor),
                                                      this->d_type);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value returned by the `visitor`.  The behavior is
    /// undefined if this variant is unset.  Note that this method is
    /// selected only if the template parameter type `VISITOR` defines a
    /// `typedef` of `ResultType` in its public interface.  Also note that
    /// this method is defined inline to work around a Windows compiler bug
    /// with SFINAE functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 1,
                            typename VISITOR::ResultType>::type
    applyRaw(const VISITOR& visitor) const {

        typedef Variant_RawVisitorHelper<typename VISITOR::ResultType,
                                         const VISITOR> Helper;

        return doApplyR<const Helper&,
                        typename VISITOR::ResultType>(Helper(&visitor),
                                                      this->d_type);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`.
    /// This method does not return a value.  The behavior is undefined if
    /// this variant is unset.  Note that this method is selected only if
    /// the template parameter type `VISITOR` does not define a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    applyRaw(VISITOR& visitor) const {

        typedef Variant_RawVisitorHelper<void, VISITOR> Helper;

        return doApply<const Helper&>(Helper(&visitor), this->d_type);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`.
    /// This method does not return a value.  The behavior is undefined if
    /// this variant is unset.  Note that this method is selected only if
    /// the template parameter type `VISITOR` does not define a `typedef` of
    /// `ResultType` in its public interface.  Also note that this method is
    /// defined inline to work around a Windows compiler bug with SFINAE
    /// functions.
    template <class VISITOR>
    typename bsl::enable_if<Variant_ReturnValueHelper<VISITOR>::value == 0,
                            void>::type
    applyRaw(const VISITOR& visitor) const {

        typedef Variant_RawVisitorHelper<void, const VISITOR> Helper;

        return doApply<const Helper&>(Helper(&visitor), this->d_type);
    }

    /// Apply the specified `visitor` to this variant by passing the value
    /// this variant currently holds to the `visitor` object's `operator()`,
    /// and return the value (of template parameter `RET_TYPE`) returned by
    /// the `visitor`.  The behavior is undefined if this variant is unset.
    template <class RET_TYPE, class VISITOR>
    RET_TYPE applyRaw(VISITOR& visitor) const;
    template <class RET_TYPE, class VISITOR>
    RET_TYPE applyRaw(const VISITOR& visitor) const;

    /// Return `true` if the value held by this variant object is of
    /// template parameter `TYPE`, and `false` otherwise.  `TYPE` must be
    /// the same as one of the types that this variant can hold.  Note that
    /// `TYPE` must be specified explicitly, e.g., `myValue.is<int>()`.
    template <class TYPE>
    bool is() const;

    /// Return `true` if this variant is currently unset, and `false`
    /// otherwise.  An unset variant does not hold a value or type.  Note
    /// that this method should be preferred over checking the type index of
    /// the variant.
    bool isUnset() const;

    /// Format this object to the specified output `stream` at the (absolute
    /// value of) the optionally specified indentation `level`, and return a
    /// reference to `stream`.  If `level` is specified, optionally specify
    /// `spacesPerLevel`, the number of spaces per indentation level for
    /// this and all of its nested objects.  If `level` is negative,
    /// suppress indentation of the first line.  If `spacesPerLevel` is
    /// negative, format the entire output on one line, suppressing all but
    /// the initial indentation (as governed by `level`).  If `stream` is
    /// not valid on entry, this operation has no effect.  Nothing is
    /// printed if this variant is unset.  Each type that may be contained
    /// by this variant shall be printable with `bdlb::PrintMethods`
    /// (typically meaning that they either declare the
    /// `bdlb::HasPrintMethod` trait or provide the `<<` output streaming
    /// operator).  See {`bdlb_printmethods`}.  The compiler will emit an
    /// error if `bdlb::PrintMethods::print` cannot be instantiated for each
    /// type that may be contained by this variant.
    bsl::ostream& print(bsl::ostream& stream,
                        int           level          = 0,
                        int           spacesPerLevel = 4) const;

    /// Return a reference providing non-modifiable access to the value of
    /// template parameter `TYPE` held by this variant object.  `TYPE` must
    /// be the same as one of the types that this variant can hold.  The
    /// behavior is undefined unless `is<TYPE>()` returns `true` and `TYPE`
    /// is not `void`.  Note that `TYPE` must be specified explicitly, e.g.,
    /// `myValue.the<int>()`.
    template <class TYPE>
    const TYPE& the() const;

    /// Return the index in the list of `TYPES` corresponding to the type of
    /// the value currently held by this variant object (starting at 1), or
    /// 0 if this object is unset.  Note that instead of switching code on
    /// the type index, calling `apply` is the preferred method of
    /// manipulating different types stored inside a variant.
    int typeIndex() const;

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    /// Return `typeid(void)`.
    ///
    /// DEPRECATED: Do not use.
    const bsl::type_info& typeInfo() const;

    /// DEPRECATED: Do not use.
    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, int version);

    /// DEPRECATED: Do not use.
    int maxSupportedBdexVersion() const;

    /// DEPRECATED: Do not use.
    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;

#endif  // BDE_OMIT_INTERNAL_DEPRECATED
};

// FREE OPERATORS

/// Return `true` if the specified `lhs` variant object has the same value
/// as the specified `rhs` variant object, and `false` otherwise.  Two
/// variant objects have the same value if they are both set and hold
/// objects of the same type and same value, or are both unset.
template <class TYPES>
bool operator==(const VariantImp<TYPES>& lhs,
                const VariantImp<TYPES>& rhs);

/// Return `true` if the specified `lhs` variant object does not have the
/// same value as the specified `rhs` variant object, and `false` otherwise.
/// Two variant objects do not have the same value if one is set and the
/// other is unset, or if they are both set but hold objects that differ in
/// type or value.
template <class TYPES>
bool operator!=(const VariantImp<TYPES>& lhs,
                const VariantImp<TYPES>& rhs);

/// Write the specified variant `object` to the specified output `stream` in
/// a single-line (human-readable) format, and return a reference to
/// `stream`.
template <class TYPES>
bsl::ostream& operator<<(bsl::ostream&            stream,
                         const VariantImp<TYPES>& object);

// FREE FUNCTIONS

/// Swap the values of the specified `a` and `b` objects.  This method
/// provides the no-throw guarantee if the `TYPE` template parameter has a
/// no-throw `swap` and the two variant objects being swapped has the same
/// type; otherwise this method provides the basic guarantee.
template <class TYPES>
void swap(VariantImp<TYPES>& a, VariantImp<TYPES>& b);

                       // ==================
                       // class Variant<...>
                       // ==================

#if defined(BDLB_VARIANT_USING_VARIADIC_TEMPLATES)
template <class ...TYPES>
class Variant : public VariantImp<typename bslmf::TypeList<TYPES...>::ListType>
                                                                              {
#else
template <class A1  = bslmf::Nil, class A2  = bslmf::Nil,
          class A3  = bslmf::Nil, class A4  = bslmf::Nil,
          class A5  = bslmf::Nil, class A6  = bslmf::Nil,
          class A7  = bslmf::Nil, class A8  = bslmf::Nil,
          class A9  = bslmf::Nil, class A10 = bslmf::Nil,
          class A11 = bslmf::Nil, class A12 = bslmf::Nil,
          class A13 = bslmf::Nil, class A14 = bslmf::Nil,
          class A15 = bslmf::Nil, class A16 = bslmf::Nil,
          class A17 = bslmf::Nil, class A18 = bslmf::Nil,
          class A19 = bslmf::Nil, class A20 = bslmf::Nil>
class Variant : public VariantImp<typename bslmf::TypeList<
                                          A1,  A2,  A3,  A4,  A5,
                                          A6,  A7,  A8,  A9,  A10,
                                          A11, A12, A13, A14, A15,
                                          A16, A17, A18, A19, A20>::ListType> {
#endif
    // This class provides a "variant" type, i.e., a type capable of storing
    // values from a list of template parameter types 'A1' to 'A20'.  Note that
    // if the number 'N' of types is smaller than 20, 'AN+1' up to 'A20'
    // default to 'bslmf::Nil', but it is more economical to use 'VariantN',
    // which accepts exactly 'N' template arguments, as this leads to shorter
    // symbols and debug string information.

    // PRIVATE TYPES
#if defined(BDLB_VARIANT_USING_VARIADIC_TEMPLATES)
    typedef VariantImp<typename bslmf::TypeList<TYPES...>::ListType>  Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant<TYPES...>                                         SelfType;
#else
    typedef VariantImp<typename bslmf::TypeList<A1,  A2,  A3,  A4,  A5,  A6,
                                                A7,  A8,  A9,  A10, A11, A12,
                                                A13, A14, A15, A16, A17, A18,
                                                A19, A20>::ListType>  Imp;

    typedef Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8,  A9,  A10,
                    A11, A12, A13, A14, A15, A16, A17, A18, A19, A20> SelfType;
        // 'SelfType' is an alias to this class.
#endif

    typedef VariantImp_Traits<typename Imp::TypeList>                 Traits;
    typedef bslmf::MovableRefUtil                                     MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant(TYPE&&                   value,
            typename bsl::enable_if<
                !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                &&
                !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                        void>::type * = 0);
#else
    Variant(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant(TYPE&&                   value,
            typename bsl::enable_if<
                !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
            bslma::Allocator>::type *basicAllocator);
#else
    Variant(bslmf::MovableRef<TYPE>  value,
            bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant(const Variant& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant(bslmf::MovableRef<Variant> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant(bslmf::MovableRef<Variant>  original,
            bslma::Allocator           *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant& operator=(const Variant& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant& operator=(bslmf::MovableRef<Variant> rhs);
};

                       // ===================
                       // class Variant2<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (2) of
/// types.  Its 2 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2>`.
template <class A1, class A2>
class Variant2 : public VariantImp<typename bslmf::TypeList2<
                                                           A1, A2>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList2<A1, A2>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant2<A1, A2>                                        SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>               Traits;
    typedef bslmf::MovableRefUtil                                   MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant2,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant2,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant2,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant2, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant2();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant2(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant2(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant2(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant2(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant2(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant2(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant2(const Variant2& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant2(bslmf::MovableRef<Variant2> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant2(bslmf::MovableRef<Variant2>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant2& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant2&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant2& operator=(const Variant2& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant2& operator=(bslmf::MovableRef<Variant2> rhs);
};

                       // ===================
                       // class Variant3<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (3) of
/// types.  Its 3 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, A3>`.
template <class A1, class A2, class A3>
class Variant3 : public VariantImp<typename bslmf::TypeList3<
                                                       A1, A2, A3>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList3<A1, A2,
                                                 A3>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant3<A1, A2, A3>                                SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant3,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant3,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant3,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant3, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant3();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant3(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant3(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant3(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant3(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant3(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant3(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant3(const Variant3& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant3(bslmf::MovableRef<Variant3> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant3(bslmf::MovableRef<Variant3>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant3& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant3&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant3& operator=(const Variant3& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant3& operator=(bslmf::MovableRef<Variant3> rhs);
};

                       // ===================
                       // class Variant4<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (4) of
/// types.  Its 4 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A4>`.
template <class A1, class A2, class A3, class A4>
class Variant4 : public VariantImp<typename bslmf::TypeList4<
                                                   A1, A2, A3, A4>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList4<A1, A2, A3,
                                                 A4>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant4<A1, A2, A3, A4>                            SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant4,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant4,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant4,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant4, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant4();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant4(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant4(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant4(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant4(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant4(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant4(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant4(const Variant4& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant4(bslmf::MovableRef<Variant4> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant4(bslmf::MovableRef<Variant4>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant4& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant4&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant4& operator=(const Variant4& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant4& operator=(bslmf::MovableRef<Variant4> rhs);
};

                       // ===================
                       // class Variant5<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (5) of
/// types.  Its 5 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A5>`.
template <class A1, class A2, class A3, class A4, class A5>
class Variant5 : public VariantImp<typename bslmf::TypeList5<
                                               A1, A2, A3, A4, A5>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList5<A1, A2, A3, A4,
                                                 A5>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant5<A1, A2, A3, A4, A5>                        SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant5,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant5,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant5,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant5, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant5();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant5(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant5(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant5(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant5(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant5(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant5(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant5(const Variant5& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant5(bslmf::MovableRef<Variant5> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant5(bslmf::MovableRef<Variant5>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant5& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant5&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant5& operator=(const Variant5& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant5& operator=(bslmf::MovableRef<Variant5> rhs);
};

                       // ===================
                       // class Variant6<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (6) of
/// types.  Its 6 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A6>`.
template <class A1, class A2, class A3, class A4, class A5, class A6>
class Variant6 : public VariantImp<typename bslmf::TypeList6<
                                           A1, A2, A3, A4, A5, A6>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList6<A1, A2, A3, A4, A5,
                                                 A6>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant6<A1, A2, A3, A4, A5, A6>                    SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant6,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant6,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant6,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant6, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant6();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant6(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant6(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant6(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant6(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant6(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant6(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant6(const Variant6& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant6(bslmf::MovableRef<Variant6> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant6(bslmf::MovableRef<Variant6>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant6& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant6&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant6& operator=(const Variant6& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant6& operator=(bslmf::MovableRef<Variant6> rhs);
};

                       // ===================
                       // class Variant7<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (7) of
/// types.  Its 7 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A7>`.
template <class A1, class A2, class A3, class A4, class A5, class A6,
          class A7>
class Variant7 : public VariantImp<typename bslmf::TypeList7<
                                       A1, A2, A3, A4, A5, A6, A7>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList7<A1, A2, A3, A4, A5, A6,
                                                 A7>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant7<A1, A2, A3, A4, A5, A6, A7>                SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant7,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant7,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant7,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant7, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant7();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant7(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant7(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant7(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant7(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant7(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant7(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant7(const Variant7& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant7(bslmf::MovableRef<Variant7> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant7(bslmf::MovableRef<Variant7>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant7& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant7&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant7& operator=(const Variant7& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant7& operator=(bslmf::MovableRef<Variant7> rhs);
};

                       // ===================
                       // class Variant8<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (8) of
/// types.  Its 8 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A8>`.
template <class A1, class A2, class A3, class A4, class A5, class A6,
          class A7, class A8>
class Variant8 : public VariantImp<typename bslmf::TypeList8<
              A1, A2, A3, A4, A5, A6, A7, A8>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList8<A1, A2, A3, A4, A5, A6, A7,
                                                 A8>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant8<A1, A2, A3, A4, A5, A6, A7, A8>            SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>           Traits;
    typedef bslmf::MovableRefUtil                               MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant8,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant8,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant8,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant8, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant8();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant8(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant8(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant8(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant8(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant8(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant8(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant8(const Variant8& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant8(bslmf::MovableRef<Variant8> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant8(bslmf::MovableRef<Variant8>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant8& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant8&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant8& operator=(const Variant8& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant8& operator=(bslmf::MovableRef<Variant8> rhs);
};

                       // ===================
                       // class Variant9<...>
                       // ===================

/// This class is a "specialization" of `Variant` for a fixed number (9) of
/// types.  Its 9 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A9>`.
template <class A1, class A2, class A3, class A4, class A5, class A6,
          class A7, class A8, class A9>
class Variant9 : public VariantImp<typename bslmf::TypeList9<
              A1, A2, A3, A4, A5, A6, A7, A8, A9>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList9<A1, A2, A3, A4, A5, A6, A7,
                                                 A8, A9>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>            SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>               Traits;
    typedef bslmf::MovableRefUtil                                   MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant9,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant9,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant9,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant9, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant9();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant9(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant9(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant9(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                 &&
                 !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                         void>::type * = 0);
#else
    Variant9(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant9(TYPE&&                   value,
             typename bsl::enable_if<
                 !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
             bslma::Allocator>::type *basicAllocator);
#else
    Variant9(bslmf::MovableRef<TYPE>  value,
             bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant9(const Variant9& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant9(bslmf::MovableRef<Variant9> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant9(bslmf::MovableRef<Variant9>  original,
             bslma::Allocator            *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant9& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant9&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant9& operator=(const Variant9& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant9& operator=(bslmf::MovableRef<Variant9> rhs);
};

                       // ====================
                       // class Variant10<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (10) of
/// types.  Its 10 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A10>`.
template <class A1, class A2, class A3, class A4, class A5, class A6,
          class A7, class A8, class A9, class A10>
class Variant10 : public VariantImp<typename bslmf::TypeList10<
                          A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList10<A1, A2, A3, A4, A5, A6, A7,
                                                  A8, A9,
                                                  A10>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>    SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant10,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant10,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant10,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant10, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant10();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant10(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant10(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant10(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant10(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant10(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant10(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant10(const Variant10& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant10(bslmf::MovableRef<Variant10> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant10(bslmf::MovableRef<Variant10>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant10& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant10&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant10& operator=(const Variant10& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant10& operator=(bslmf::MovableRef<Variant10> rhs);
};

                       // ====================
                       // class Variant11<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (11) of
/// types.  Its 11 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A11>`.
template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
class Variant11 : public VariantImp<typename bslmf::TypeList11<
                     A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList11<A1, A2, A3, A4, A5, A6, A7,
                                                  A8, A9, A10,
                                                  A11>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10,
                      A11>                                        SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant11,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant11,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant11,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant11, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant11();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant11(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant11(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant11(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant11(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant11(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant11(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant11(const Variant11& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant11(bslmf::MovableRef<Variant11> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant11(bslmf::MovableRef<Variant11>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant11& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant11&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant11& operator=(const Variant11& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant11& operator=(bslmf::MovableRef<Variant11> rhs);
};

                       // ====================
                       // class Variant12<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (12) of
/// types.  Its 12 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A12>`.
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
class Variant12 : public VariantImp<typename bslmf::TypeList12<
              A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList12<A1, A2, A3, A4,  A5, A6,
                                                  A7, A8, A9, A10, A11,
                                                  A12>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant12<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10,
                      A11, A12>                                   SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant12,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant12,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant12,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant12, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant12();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant12(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant12(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant12(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant12(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant12(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant12(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant12(const Variant12& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant12(bslmf::MovableRef<Variant12> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant12(bslmf::MovableRef<Variant12>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant12& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant12&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant12& operator=(const Variant12& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant12& operator=(bslmf::MovableRef<Variant12> rhs);
};

                       // ====================
                       // class Variant13<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (13) of
/// types.  Its 13 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A13>`.
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
class Variant13 : public VariantImp<typename bslmf::TypeList13<
           A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList13<A1, A2, A3, A4,  A5,  A6,
                                                  A7, A8, A9, A10, A11, A12,
                                                  A13>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant13<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9,
                      A10, A11, A12, A13>                         SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant13,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant13,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant13,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant13, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant13();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant13(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant13(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant13(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant13(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant13(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant13(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant13(const Variant13& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant13(bslmf::MovableRef<Variant13> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant13(bslmf::MovableRef<Variant13>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant13& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant13&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant13& operator=(const Variant13& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant13& operator=(bslmf::MovableRef<Variant13> rhs);
};

                       // ====================
                       // class Variant14<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (14) of
/// types.  Its 14 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A14>`.
template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
class Variant14 : public VariantImp<typename bslmf::TypeList14<
                                               A1,  A2,  A3,  A4,  A5,
                                               A6,  A7,  A8,  A9,  A10,
                                               A11, A12, A13, A14>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList14<A1,  A2,  A3,  A4,  A5,  A6,
                                                  A7,  A8,  A9,  A10, A11, A12,
                                                  A13,
                                                  A14>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant14<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9,
                      A10, A11, A12, A13, A14>                    SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant14,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant14,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant14,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant14, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant14();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant14(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant14(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant14(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant14(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant14(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant14(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant14(const Variant14& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant14(bslmf::MovableRef<Variant14> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant14(bslmf::MovableRef<Variant14>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant14& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant14&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant14& operator=(const Variant14& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant14& operator=(bslmf::MovableRef<Variant14> rhs);
};

                       // ====================
                       // class Variant15<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (15) of
/// types.  Its 15 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A15>`.
template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
class Variant15 : public VariantImp<typename bslmf::TypeList15<
                                          A1,  A2,  A3,  A4,  A5,
                                          A6,  A7,  A8,  A9,  A10,
                                          A11, A12, A13, A14, A15>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList15<A1,  A2, A3, A4,  A5,  A6,
                                                  A7,  A8, A9, A10, A11, A12,
                                                  A13, A14,
                                                  A15>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant15<A1,  A2,  A3,  A4,  A5,  A6, A7, A8, A9,
                      A10, A11, A12, A13, A14, A15>               SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant15,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant15,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant15,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant15, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant15();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant15(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant15(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant15(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant15(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant15(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant15(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant15(const Variant15& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant15(bslmf::MovableRef<Variant15> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant15(bslmf::MovableRef<Variant15>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant15& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant15&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant15& operator=(const Variant15& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant15& operator=(bslmf::MovableRef<Variant15> rhs);
};

                       // ====================
                       // class Variant16<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (16) of
/// types.  Its 16 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A16>`.
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
class Variant16 : public VariantImp<typename bslmf::TypeList16<
                                                       A1,  A2,  A3,  A4,  A5,
                                                       A6,  A7,  A8,  A9,  A10,
                                                       A11, A12, A13, A14, A15,
                                                       A16>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList16<A1,  A2,  A3, A4,  A5,  A6,
                                                  A7,  A8,  A9, A10, A11, A12,
                                                  A13, A14, A15,
                                                  A16>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant16<A1,  A2,  A3,  A4,  A5,  A6,  A7, A8, A9,
                      A10, A11, A12, A13, A14, A15, A16>          SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant16,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant16,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant16,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant16, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant16();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant16(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant16(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant16(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant16(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant16(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant16(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant16(const Variant16& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant16(bslmf::MovableRef<Variant16> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant16(bslmf::MovableRef<Variant16>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant16& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant16&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant16& operator=(const Variant16& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant16& operator=(bslmf::MovableRef<Variant16> rhs);
};

                       // ====================
                       // class Variant17<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (17) of
/// types.  Its 17 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A17>`.
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
class Variant17 : public VariantImp<typename bslmf::TypeList17<
                                                       A1,  A2,  A3,  A4,  A5,
                                                       A6,  A7,  A8,  A9,  A10,
                                                       A11, A12, A13, A14, A15,
                                                       A16, A17>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList17<A1,  A2,  A3,  A4,  A5,  A6,
                                                  A7,  A8,  A9,  A10, A11, A12,
                                                  A13, A14, A15, A16,
                                                  A17>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant17<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9,
                      A10, A11, A12, A13, A14, A15, A16, A17>     SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant17,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant17,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant17,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant17, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant17();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant17(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant17(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant17(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant17(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant17(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant17(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant17(const Variant17& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant17(bslmf::MovableRef<Variant17> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant17(bslmf::MovableRef<Variant17>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant17& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant17&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant17& operator=(const Variant17& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant17& operator=(bslmf::MovableRef<Variant17> rhs);
};

                       // ====================
                       // class Variant18<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (18) of
/// types.  Its 18 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A18>`.
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
class Variant18 : public VariantImp<typename bslmf::TypeList18<
                                                    A1,  A2,  A3,  A4,  A5,
                                                    A6,  A7,  A8,  A9,  A10,
                                                    A11, A12, A13, A14, A15,
                                                    A16, A17, A18>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList18<A1,  A2,  A3,  A4,  A5,  A6,
                                                  A7,  A8,  A9,  A10, A11, A12,
                                                  A13, A14, A15, A16, A17,
                                                  A18>::ListType>  Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant18<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8,  A9,
                      A10, A11, A12, A13, A14, A15, A16, A17, A18> SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>              Traits;
    typedef bslmf::MovableRefUtil                                  MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant18,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant18,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant18,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant18, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant18();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant18(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant18(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant18(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant18(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant18(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant18(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant18(const Variant18& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant18(bslmf::MovableRef<Variant18> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant18(bslmf::MovableRef<Variant18>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant18& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant18&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant18& operator=(const Variant18& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant18& operator=(bslmf::MovableRef<Variant18> rhs);
};

                       // ====================
                       // class Variant19<...>
                       // ====================

/// This class is a "specialization" of `Variant` for a fixed number (19) of
/// types.  Its 19 template arguments *must* all be specified (none are
/// defaulted to `bslmf::Nil`).  It provides the same functionality as
/// `Variant<A1, A2, ..., A19>`.
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
class Variant19 : public VariantImp<typename bslmf::TypeList19<
                                               A1,  A2,  A3,  A4,  A5,
                                               A6,  A7,  A8,  A9,  A10,
                                               A11, A12, A13, A14, A15,
                                               A16, A17, A18, A19>::ListType> {

    // PRIVATE TYPES
    typedef VariantImp<typename bslmf::TypeList19<A1,  A2,  A3,  A4,  A5,  A6,
                                                  A7,  A8,  A9,  A10, A11, A12,
                                                  A13, A14, A15, A16, A17, A18,
                                                  A19>::ListType> Imp;

    /// `SelfType` is an alias to this class.
    typedef Variant19<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8,  A9,
                      A10, A11, A12, A13, A14, A15, A16, A17, A18,
                      A19>                                        SelfType;

    typedef VariantImp_Traits<typename Imp::TypeList>             Traits;
    typedef bslmf::MovableRefUtil                                 MoveUtil;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant19,
                                      bslma::UsesBslmaAllocator,
                                      Traits::k_VARIANT_USES_BSLMA_ALLOCATOR);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant19,
                                      bslmf::IsBitwiseCopyable,
                                      Traits::k_VARIANT_IS_BITWISE_COPYABLE);
    BSLMF_NESTED_TRAIT_DECLARATION_IF(Variant19,
                                      bslmf::IsBitwiseMoveable,
                                      Traits::k_VARIANT_IS_BITWISE_MOVEABLE);
    BSLMF_NESTED_TRAIT_DECLARATION(Variant19, HasPrintMethod);

    // CREATORS

    /// Create a variant object in the unset state that uses the currently
    /// installed default allocator to supply memory.
    Variant19();

    /// Create a variant object with the specified `valueOrAllocator` that
    /// can be either a value of a type that the variant can hold or an
    /// allocator to supply memory.  If `valueOrAllocator` is not a
    /// `bslma::Allocator *`, then the variant will hold the value and type
    /// of `valueOrAllocator`, and use the currently installed default
    /// allocator to supply memory.  Otherwise, the variant will be unset
    /// and use `valueOrAllocator` to supply memory.  `TYPE_OR_ALLOCATOR`
    /// must be the same as one of the types that this variant can hold or
    /// be convertible to `bslma::Allocator *`.  Note that this
    /// parameterized constructor is defined instead of two constructors
    /// (one taking a `bslma::Allocator *` and the other not) because
    /// template parameter arguments are always a better match than
    /// derived-to-base conversion (a concrete allocator pointer converted
    /// to `bslma::Allocator *`).
    template <class TYPE_OR_ALLOCATOR>
    explicit
    Variant19(const TYPE_OR_ALLOCATOR& valueOrAllocator);

    /// Create a variant object having the specified `value` of template
    /// parameter `TYPE` and that uses the specified `basicAllocator` to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.  `TYPE` must be the same as one of the
    /// types that this variant can hold.
    template <class TYPE>
    Variant19(const TYPE& value, bslma::Allocator *basicAllocator);

    template <class TYPE>
    explicit
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant19(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
                  &&
                  !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                          void>::type * = 0);
#else
    Variant19(bslmf::MovableRef<TYPE>  value);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' by moving the contents of 'value' to the
        // newly-created object.  Use the currently installed default allocator
        // to supply memory.  'value' is left in a valid but unspecified state.
        // 'TYPE' must be the same as one of the types that this variant can
        // hold.  Note that in C++11 mode, this method does not participate in
        // overload resolution if it would lead to ambiguity with the move
        // constructor that does not take an allocator (below) or with the
        // constructor taking a 'valueOrAllocator' (above).

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Variant19(TYPE&&                   value,
              typename bsl::enable_if<
                  !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
              bslma::Allocator>::type *basicAllocator);
#else
    Variant19(bslmf::MovableRef<TYPE>  value,
              bslma::Allocator        *basicAllocator);
#endif
        // Create a variant object having the specified 'value' of template
        // parameter 'TYPE' that uses the specified 'basicAllocator' to supply
        // memory.  If 'basicAllocator' is 0, the currently installed default
        // allocator is used.  The contents of 'value' are moved to the
        // newly-created object with 'value' left in a valid but unspecified
        // state.  'TYPE' must be the same as one of the types that this
        // variant can hold.  Note that in C++11 mode, this method does not
        // participate in overload resolution if it would lead to ambiguity
        // with the move constructor that takes an allocator (below).

    /// Create a variant object having the type and value of the specified
    /// `original` variant.  Optionally specify a `basicAllocator` used to
    /// supply memory.  If `basicAllocator` is 0, the currently installed
    /// default allocator is used.
    Variant19(const Variant19& original, bslma::Allocator *basicAllocator = 0);

    /// Create a variant object having the type and value of the specified
    /// `original` object by moving the contents of `original` to the
    /// newly-created object.  The allocator associated with `original` (if
    /// any) is propagated for use in the newly-created object.  `original`
    /// is left in a valid but unspecified state.
    Variant19(bslmf::MovableRef<Variant19> original);

    /// Create a variant object having the type and value of the specified
    /// `original` object that uses the specified `basicAllocator` to supply
    /// memory.  If `basicAllocator` is 0, the currently installed default
    /// allocator is used.  The contents of `original` are moved to the
    /// newly-created object with `original` left in a valid but unspecified
    /// state.
    Variant19(bslmf::MovableRef<Variant19>  original,
              bslma::Allocator             *basicAllocator);

    // MANIPULATORS

    /// Assign to this object the specified `value` of template parameter
    /// `TYPE`, and return a reference providing modifiable access to this
    /// object.  The value currently held by this variant (if any) is
    /// destroyed if that value's type is not the same as `TYPE`.  `TYPE`
    /// must be the same as one of the types that this variant can hold.
    template <class TYPE>
    Variant19& operator=(const TYPE& value);

    template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    typename bsl::enable_if<
        !bsl::is_same<SelfType,
                      typename bsl::remove_cvref<TYPE>::type>::value,
    SelfType>::type&
    operator=(TYPE&&                  value);
#else
    Variant19&
    operator=(bslmf::MovableRef<TYPE> value);
#endif
        // Assign to this object the specified 'value' of template parameter
        // 'TYPE', and return a reference providing modifiable access to this
        // object.  The contents of 'value' are moved to this object with
        // 'value' left in a valid but unspecified state.  The value currently
        // held by this variant (if any) is destroyed if that value's type is
        // not the same as 'TYPE'.  'TYPE' must be the same as one of the types
        // that this variant can hold.  Note that in C++11 mode, this method
        // does not participate in overload resolution if it would lead to
        // ambiguity with the move-assignment operator (below).

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.
    Variant19& operator=(const Variant19& rhs);

    /// Assign to this object the type and value currently held by the
    /// specified `rhs` object, and return a reference providing modifiable
    /// access to this object.  The value currently held by this variant
    /// (if any) is destroyed if that value's type is not the same as the
    /// type held by the `rhs` object.  The contents of `rhs` are either
    /// move-inserted into or move-assigned to this object with `rhs` left
    /// in a valid but unspecified state.
    Variant19& operator=(bslmf::MovableRef<Variant19> rhs);
};

// ---- Anything below this line is implementation specific.  Do not use.  ----

               // =====================================
               // struct Variant_TypeIndex<TYPES, TYPE>
               // =====================================

/// Component-private meta-function.  Do not use.  This meta-function
/// computes the index of the template parameter `TYPE` in the template
/// parameter list of `TYPES`.
template <class TYPES, class TYPE>
struct Variant_TypeIndex {

    enum {
        value = bsl::is_same<
                      typename bslmf::TypeListTypeOf< 1, TYPES>::TypeOrDefault,
                      TYPE>::value ?  1
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 2, TYPES>::TypeOrDefault,
                      TYPE>::value ?  2
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 3, TYPES>::TypeOrDefault,
                      TYPE>::value ?  3
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 4, TYPES>::TypeOrDefault,
                      TYPE>::value ?  4
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 5, TYPES>::TypeOrDefault,
                      TYPE>::value ?  5
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 6, TYPES>::TypeOrDefault,
                      TYPE>::value ?  6
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 7, TYPES>::TypeOrDefault,
                      TYPE>::value ?  7
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 8, TYPES>::TypeOrDefault,
                      TYPE>::value ?  8
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf< 9, TYPES>::TypeOrDefault,
                      TYPE>::value ?  9
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<10, TYPES>::TypeOrDefault,
                      TYPE>::value ? 10
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<11, TYPES>::TypeOrDefault,
                      TYPE>::value ? 11
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<12, TYPES>::TypeOrDefault,
                      TYPE>::value ? 12
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<13, TYPES>::TypeOrDefault,
                      TYPE>::value ? 13
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<14, TYPES>::TypeOrDefault,
                      TYPE>::value ? 14
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<15, TYPES>::TypeOrDefault,
                      TYPE>::value ? 15
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<16, TYPES>::TypeOrDefault,
                      TYPE>::value ? 16
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<17, TYPES>::TypeOrDefault,
                      TYPE>::value ? 17
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<18, TYPES>::TypeOrDefault,
                      TYPE>::value ? 18
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<19, TYPES>::TypeOrDefault,
                      TYPE>::value ? 19
              : bsl::is_same<
                      typename bslmf::TypeListTypeOf<20, TYPES>::TypeOrDefault,
                      TYPE>::value ? 20
              : bsl::is_convertible<TYPE, bslma::Allocator *>::value
                                   ? 21
              : 0
    };

    BSLMF_ASSERT(0 != value);

#if defined(BDLB_VARIANT_USING_VARIADIC_TEMPLATES)
    // See 'testCase17' in the test driver for code snippets that motivate this
    // compile-time assertion (see the "out of bounds" comments).  In C++03,
    // 'TYPES::LENGTH' yields an incorrect value if 'TYPES' has a trailing
    // 'bslmf::Nil' (unless the variant is declared using 'VariantN').  It is
    // arguably dubious to allow 'bslmf::Nil' as one of the types that a
    // variant may hold, but there is such use in production code that needs to
    // be considered if that "feature" is to be suppressed.  This would do it:
    //..
    //  BSLMF_ASSERT((!bsl::is_same<TYPE, bslmf::Nil>::value));
    //..

    // TBD The following breaks compilation of some client code in C++11 mode
    // that is most likely misusing 'bslmf::Nil'.
    // BSLMF_ASSERT(((int)value <= (int)TYPES::LENGTH || 21 == value));
#endif
};

               // ======================================
               // struct Variant_DefaultConstructVisitor
               // ======================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, will create a default
/// instance of `TYPE`.
struct Variant_DefaultConstructVisitor {

    // PUBLIC DATA
    bslma::Allocator *d_allocator_p;

    // CREATORS
    explicit
    Variant_DefaultConstructVisitor(bslma::Allocator *allocator)
    : d_allocator_p(allocator)
    {
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(TYPE& value) const
    {
        bslma::ConstructionUtil::construct(&value, d_allocator_p);
    }
};

                // ===================================
                // struct Variant_CopyConstructVisitor
                // ===================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, will copy-insert that
/// instance to create an instance of the same `TYPE` in an uninitialized
/// buffer specified at construction of this visitor.
struct Variant_CopyConstructVisitor {

    // PUBLIC DATA
    void             *d_buffer_p;
    bslma::Allocator *d_allocator_p;

    // CREATORS
    Variant_CopyConstructVisitor(void *buffer, bslma::Allocator *allocator)
    : d_buffer_p(buffer)
    , d_allocator_p(allocator)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(const TYPE& value) const
    {
        bslma::ConstructionUtil::construct(
                                          reinterpret_cast<TYPE *>(d_buffer_p),
                                          d_allocator_p,
                                          value);
    }
};

                // ===================================
                // struct Variant_MoveConstructVisitor
                // ===================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, will move-insert that
/// instance to create an instance of the same `TYPE` in an uninitialized
/// buffer specified at construction of this visitor.
struct Variant_MoveConstructVisitor {

    // PUBLIC DATA
    void             *d_buffer_p;
    bslma::Allocator *d_allocator_p;

    // CREATORS
    Variant_MoveConstructVisitor(void *buffer, bslma::Allocator *allocator)
    : d_buffer_p(buffer)
    , d_allocator_p(allocator)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(TYPE& value) const
    {
        bslma::ConstructionUtil::construct(
                                          reinterpret_cast<TYPE *>(d_buffer_p),
                                          d_allocator_p,
                                          bslmf::MovableRefUtil::move(value));
    }
};

                  // ================================
                  // struct Variant_DestructorVisitor
                  // ================================

/// This visitor, when invoked as a function object on an instance of some
/// template parameter `TYPE`, will destroy that instance.
struct Variant_DestructorVisitor {

    // ACCESSORS
    template <class TYPE>
    void operator()(TYPE& object) const
    {
        bslma::DestructionUtil::destroy(&object);
    }
};

                    // ================================
                    // struct Variant_CopyAssignVisitor
                    // ================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, will copy-assign that
/// instance to the instance of the same `TYPE` held in a buffer specified
/// at construction of this visitor.
struct Variant_CopyAssignVisitor {

    // PUBLIC DATA
    void *d_buffer_p;

    // CREATORS
    explicit
    Variant_CopyAssignVisitor(void *buffer)
    : d_buffer_p(buffer)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(const TYPE& value)
    {
        *reinterpret_cast<TYPE *>(d_buffer_p) = value;
    }
};

                    // ================================
                    // struct Variant_MoveAssignVisitor
                    // ================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, will move-assign that
/// instance to the instance of the same `TYPE` held in a buffer specified
/// at construction of this visitor.
struct Variant_MoveAssignVisitor {

    // PUBLIC DATA
    void *d_buffer_p;

    // CREATORS
    explicit
    Variant_MoveAssignVisitor(void *buffer)
    : d_buffer_p(buffer)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(TYPE& value)
    {
        *reinterpret_cast<TYPE *>(d_buffer_p) =
                                            bslmf::MovableRefUtil::move(value);
    }
};

                    // ==========================
                    // struct Variant_SwapVisitor
                    // ==========================

/// This visitor swaps the variant object data that it holds with another
/// variant object data of parameterize `TYPE`.  It requires that the two
/// variant objects being swapped contain data of the same type, and use the
/// same allocator.
struct Variant_SwapVisitor {

    // PUBLIC DATA
    void *d_buffer_p;

    // CREATORS
    explicit
    Variant_SwapVisitor(void *buffer)
    : d_buffer_p(buffer)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // MANIPULATORS
    template <class TYPE>
    void operator()(TYPE& value)
    {
        bslalg::SwapUtil::swap(reinterpret_cast<TYPE *>(d_buffer_p), &value);
    }
};

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

                 // ==================================
                 // struct Variant_BdexStreamInVisitor
                 // ==================================

/// This visitor, when invoked as a non-modifiable function object on an
/// initialized instance of some parameterized `TYPE`, will stream in
/// a value of the same `TYPE` into that instance from a stream specified at
/// construction of this visitor,  using a version also specified at
/// construction of this visitor.
template <class STREAM>
struct Variant_BdexStreamInVisitor {

    // PUBLIC DATA
    STREAM& d_stream;   // held, not owned
    int     d_version;  // BDEX version

    // CREATORS
    Variant_BdexStreamInVisitor(STREAM& stream, int version)
    : d_stream(stream)
    , d_version(version)
    {
    }

    // ACCESSORS
    template <class VALUETYPE>
    inline
    void operator()(VALUETYPE& object) const
    {
        bslx::InStreamFunctions::bdexStreamIn(d_stream, object, d_version);
    }

    inline
    void operator()(bslmf::Nil) const
    {
        // no op
    }
};

                // ===================================
                // struct Variant_BdexStreamOutVisitor
                // ===================================

/// This visitor, when invoked as a non-modifiable function object on an
/// initialized instance of some parameterized `TYPE`, will stream out the
/// value of that instance into a stream specified at construction of this
/// visitor, using a version also specified at construction of this
/// visitor.
template <class STREAM>
struct Variant_BdexStreamOutVisitor {

    // PUBLIC DATA
    STREAM& d_stream;   // held, not owned
    int     d_version;  // BDEX version

    // CREATORS
    Variant_BdexStreamOutVisitor(STREAM& stream, int version)
    : d_stream(stream)
    , d_version(version)
    {
    }

    // ACCESSORS
    template <class VALUETYPE>
    inline
    void operator()(const VALUETYPE& object) const
    {
        bslx::OutStreamFunctions::bdexStreamOut(d_stream, object, d_version);
    }

    inline
    void operator()(bslmf::Nil) const
    {
        // no op
    }
};
#endif

                    // ===========================
                    // struct Variant_PrintVisitor
                    // ===========================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, writes the value of that
/// instance to a stream specified at construction of this visitor, using
/// spacing information also specified at construction.
struct Variant_PrintVisitor {

    // PUBLIC DATA
    bsl::ostream *d_stream_p;        // held, not owned
    int           d_level;
    int           d_spacesPerLevel;

    // CREATORS
    Variant_PrintVisitor(bsl::ostream *stream,
                         int           level,
                         int           spacesPerLevel)
    : d_stream_p(stream)
    , d_level(level)
    , d_spacesPerLevel(spacesPerLevel)
    {
        BSLS_ASSERT_SAFE(d_stream_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(const TYPE& value) const
    {
        PrintMethods::print(*d_stream_p, value, d_level, d_spacesPerLevel);
    }

    void operator()(bslmf::Nil) const
    {
        // no op
    }
};

                 // ==================================
                 // struct Variant_EqualityTestVisitor
                 // ==================================

/// This visitor, when invoked as a non-modifiable function object on an
/// instance of some template parameter `TYPE`, tests the equality of the
/// value of that instance and of another instance held in a buffer
/// specified at construction of this visitor, and stores the result into
/// its publicly accessible `d_result` member.
struct Variant_EqualityTestVisitor {

    // PUBLIC DATA
    mutable bool  d_result;
    const void   *d_buffer_p;  // held, not owned

    // CREATORS
    explicit
    Variant_EqualityTestVisitor(const void *buffer)
    : d_result(true)
    , d_buffer_p(buffer)
    {
        BSLS_ASSERT_SAFE(d_buffer_p);
    }

    // ACCESSORS
    template <class TYPE>
    void operator()(const TYPE& value) const
    {
        d_result = *reinterpret_cast<const TYPE *>(d_buffer_p) == value;
    }

    void operator()(bslmf::Nil) const
    {
        d_result = true;
    }
};

// ============================================================================
//                           INLINE DEFINITIONS
// ============================================================================

                   // -------------------------------------
                   // class VariantImp_AllocatorBase<TYPES>
                   // -------------------------------------

// CREATORS
template <class TYPES>
inline
VariantImp_AllocatorBase<TYPES>::
VariantImp_AllocatorBase(int type, bslma::Allocator *basicAllocator)
: d_type(type)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}

template <class TYPES>
inline
VariantImp_AllocatorBase<TYPES>::
VariantImp_AllocatorBase(int, bslma::Allocator *basicAllocator, bsl::true_type)
: d_type(0)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}

template <class TYPES>
template <class TYPE>
inline
VariantImp_AllocatorBase<TYPES>::
VariantImp_AllocatorBase(int type, const TYPE&, bsl::false_type)
: d_type(type)
, d_allocator_p(bslma::Default::allocator(0))
{
}

// ACCESSORS
template <class TYPES>
inline
bslma::Allocator *
VariantImp_AllocatorBase<TYPES>::getAllocator() const
{
    return d_allocator_p;
}

                  // ---------------------------------------
                  // class VariantImp_NoAllocatorBase<TYPES>
                  // ---------------------------------------

// CREATORS
template <class TYPES>
inline
VariantImp_NoAllocatorBase<TYPES>::
VariantImp_NoAllocatorBase(int type, bslma::Allocator *)
: d_type(type)
{
}

template <class TYPES>
inline
VariantImp_NoAllocatorBase<TYPES>::
VariantImp_NoAllocatorBase(int, bslma::Allocator *, bsl::true_type)
: d_type(0)
{
}

template <class TYPES>
template <class TYPE>
inline
VariantImp_NoAllocatorBase<TYPES>::
VariantImp_NoAllocatorBase(int type, const TYPE&, bsl::false_type)
: d_type(type)
{
}

// ACCESSORS
template <class TYPES>
inline
bslma::Allocator *
VariantImp_NoAllocatorBase<TYPES>::getAllocator() const
{
    return 0;
}

                       // ------------------------------
                       // class Variant_RawVisitorHelper
                       // ------------------------------

// CREATORS
template <class RESULT_TYPE, class VISITOR>
inline
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::
Variant_RawVisitorHelper(VISITOR *visitor)
: d_visitor(visitor)
{
    BSLS_ASSERT_SAFE(0 != visitor);
}

// MANIPULATORS
template <class RESULT_TYPE, class VISITOR>
template <class ARGUMENT_TYPE>
inline
RESULT_TYPE
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::operator()(
                                                       ARGUMENT_TYPE& argument)
{
    return static_cast<RESULT_TYPE>((*d_visitor)(argument));
}

template <class RESULT_TYPE, class VISITOR>
template <class ARGUMENT_TYPE>
inline
RESULT_TYPE
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::operator()(
                                                 const ARGUMENT_TYPE& argument)
{
    return static_cast<RESULT_TYPE>((*d_visitor)(argument));
}

// ACCESSORS
template <class RESULT_TYPE, class VISITOR>
template <class ARGUMENT_TYPE>
inline
RESULT_TYPE
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::operator()(
                                                 ARGUMENT_TYPE& argument) const
{
    return static_cast<RESULT_TYPE>((*d_visitor)(argument));
}

template <class RESULT_TYPE, class VISITOR>
template <class ARGUMENT_TYPE>
inline
RESULT_TYPE
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::operator()(
                                           const ARGUMENT_TYPE& argument) const
{
    return static_cast<RESULT_TYPE>((*d_visitor)(argument));
}

template <class RESULT_TYPE, class VISITOR>
RESULT_TYPE
Variant_RawVisitorHelper<RESULT_TYPE, VISITOR>::operator()(bslmf::Nil) const
{
    BSLS_ASSERT_INVOKE_NORETURN("unreachable");
}

                        // -----------------------
                        // class VariantImp<TYPES>
                        // -----------------------

// PRIVATE MANIPULATORS
template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor, bsl::false_type)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    visitor(reinterpret_cast<BufferType *>(&this->d_value)->object());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor, bsl::true_type)
{
    bslmf::Nil nil = bslmf::Nil();
    visitor(nil);
}

template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor)
{
    typedef typename bsl::is_same<TYPE, bslmf::Nil>::type IsUnset;
    applyImp<TYPE, VISITOR_REF>(visitor, IsUnset());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF visitor, bsl::false_type)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    return visitor(reinterpret_cast<BufferType *>(&this->d_value)->object());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF visitor, bsl::true_type)
{
    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF visitor)
{
    typedef typename bsl::is_same<TYPE, bslmf::Nil>::type IsUnset;
    return applyImpR<TYPE, VISITOR_REF, RET_TYPE>(visitor, IsUnset());
}

template <class TYPES>
template <class TYPE, class SOURCE_TYPE>
void VariantImp<TYPES>::assignImp(const SOURCE_TYPE& value)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    reset();
    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     value);
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;
}

template <class TYPES>
template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
void VariantImp<TYPES>::assignImp(TYPE&&                  value)
#else
void VariantImp<TYPES>::assignImp(bslmf::MovableRef<TYPE> value)
#endif
{
    typedef bsls::ObjectBuffer<typename bsl::remove_reference<TYPE>::type>
                                                                    BufferType;

    reset();

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     bslmf::MovableRefUtil::move(lvalue));
#endif

    this->d_type =
          Variant_TypeIndex<TYPES,
                            typename bsl::remove_reference<TYPE>::type>::value;
}

template <class TYPES>
template <class VISITOR_REF>
void VariantImp<TYPES>::doApply(VISITOR_REF visitor, int type)
{
    switch (type) {
      case 0: {
        BSLS_ASSERT(0 == "'doApply' invoked on an unset variant");
      } break;
      case 1: {
        applyImp<typename Base::Type1, VISITOR_REF>(visitor);
      } break;
      case 2: {
        applyImp<typename Base::Type2, VISITOR_REF>(visitor);
      } break;
      case 3: {
        applyImp<typename Base::Type3, VISITOR_REF>(visitor);
      } break;
      case 4: {
        applyImp<typename Base::Type4, VISITOR_REF>(visitor);
      } break;
      case 5: {
        applyImp<typename Base::Type5, VISITOR_REF>(visitor);
      } break;
      case 6: {
        applyImp<typename Base::Type6, VISITOR_REF>(visitor);
      } break;
      case 7: {
        applyImp<typename Base::Type7, VISITOR_REF>(visitor);
      } break;
      case 8: {
        applyImp<typename Base::Type8, VISITOR_REF>(visitor);
      } break;
      case 9: {
        applyImp<typename Base::Type9, VISITOR_REF>(visitor);
      } break;
      case 10: {
        applyImp<typename Base::Type10, VISITOR_REF>(visitor);
      } break;
      case 11: {
        applyImp<typename Base::Type11, VISITOR_REF>(visitor);
      } break;
      case 12: {
        applyImp<typename Base::Type12, VISITOR_REF>(visitor);
      } break;
      case 13: {
        applyImp<typename Base::Type13, VISITOR_REF>(visitor);
      } break;
      case 14: {
        applyImp<typename Base::Type14, VISITOR_REF>(visitor);
      } break;
      case 15: {
        applyImp<typename Base::Type15, VISITOR_REF>(visitor);
      } break;
      case 16: {
        applyImp<typename Base::Type16, VISITOR_REF>(visitor);
      } break;
      case 17: {
        applyImp<typename Base::Type17, VISITOR_REF>(visitor);
      } break;
      case 18: {
        applyImp<typename Base::Type18, VISITOR_REF>(visitor);
      } break;
      case 19: {
        applyImp<typename Base::Type19, VISITOR_REF>(visitor);
      } break;
      case 20: {
        applyImp<typename Base::Type20, VISITOR_REF>(visitor);
      } break;
      default: {
        BSLS_ASSERT_UNREACHABLE("Variant type index exceeds maximum");
      } break;
    }
}

template <class TYPES>
template <class TYPE>
inline
void VariantImp<TYPES>::create(const TYPE& value, bsl::false_type)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     value);
}

template <class TYPES>
inline
void VariantImp<TYPES>::create(bslma::Allocator *, bsl::true_type)
{
}

template <class TYPES>
template <class VISITOR_REF, class RET_TYPE>
RET_TYPE VariantImp<TYPES>::doApplyR(VISITOR_REF visitor, int type)
{
    switch (type) {
      case 0: {
        BSLS_ASSERT_INVOKE_NORETURN("'doApplyR' invoked on an unset variant");
      } break;
      case 1: {
        return applyImpR<typename Base::Type1,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 2: {
        return applyImpR<typename Base::Type2,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 3: {
        return applyImpR<typename Base::Type3,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 4: {
        return applyImpR<typename Base::Type4,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 5: {
        return applyImpR<typename Base::Type5,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 6: {
        return applyImpR<typename Base::Type6,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 7: {
        return applyImpR<typename Base::Type7,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 8: {
        return applyImpR<typename Base::Type8,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 9: {
        return applyImpR<typename Base::Type9,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 10: {
        return applyImpR<typename Base::Type10,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 11: {
        return applyImpR<typename Base::Type11,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 12: {
        return applyImpR<typename Base::Type12,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 13: {
        return applyImpR<typename Base::Type13,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 14: {
        return applyImpR<typename Base::Type14,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 15: {
        return applyImpR<typename Base::Type15,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 16: {
        return applyImpR<typename Base::Type16,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 17: {
        return applyImpR<typename Base::Type17,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 18: {
        return applyImpR<typename Base::Type18,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 19: {
        return applyImpR<typename Base::Type19,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 20: {
        return applyImpR<typename Base::Type20,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      default: {
        BSLS_ASSERT_INVOKE_NORETURN("Unreachable by design!");
      } break;
    }
}

// PRIVATE ACCESSORS
template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor, bsl::false_type) const
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    visitor(reinterpret_cast<const BufferType *>(&this->d_value)->object());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor, bsl::true_type) const
{
    bslmf::Nil nil = bslmf::Nil();
    visitor(nil);
}

template <class TYPES>
template <class TYPE, class VISITOR_REF>
inline
void VariantImp<TYPES>::applyImp(VISITOR_REF visitor) const
{
    typedef typename bsl::is_same<TYPE, bslmf::Nil>::type IsUnset;
    applyImp<TYPE, VISITOR_REF>(visitor, IsUnset());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF     visitor,
                                      bsl::false_type) const
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    return visitor(reinterpret_cast<const BufferType *>(
                                                    &this->d_value)->object());
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF visitor,
                                      bsl::true_type) const
{
    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class TYPE, class VISITOR_REF, class RET_TYPE>
inline
RET_TYPE VariantImp<TYPES>::applyImpR(VISITOR_REF visitor) const
{
    typedef typename bsl::is_same<TYPE, bslmf::Nil>::type IsUnset;
    return applyImpR<TYPE, VISITOR_REF, RET_TYPE>(visitor, IsUnset());
}

template <class TYPES>
template <class VISITOR_REF>
void VariantImp<TYPES>::doApply(VISITOR_REF visitor, int type) const
{
    switch (type) {
      case 0: {
        BSLS_ASSERT_INVOKE_NORETURN("'doApply' invoked on an unset variant");
      } break;
      case 1: {
        applyImp<typename Base::Type1, VISITOR_REF>(visitor);
      } break;
      case 2: {
        applyImp<typename Base::Type2, VISITOR_REF>(visitor);
      } break;
      case 3: {
        applyImp<typename Base::Type3, VISITOR_REF>(visitor);
      } break;
      case 4: {
        applyImp<typename Base::Type4, VISITOR_REF>(visitor);
      } break;
      case 5: {
        applyImp<typename Base::Type5, VISITOR_REF>(visitor);
      } break;
      case 6: {
        applyImp<typename Base::Type6, VISITOR_REF>(visitor);
      } break;
      case 7: {
        applyImp<typename Base::Type7, VISITOR_REF>(visitor);
      } break;
      case 8: {
        applyImp<typename Base::Type8, VISITOR_REF>(visitor);
      } break;
      case 9: {
        applyImp<typename Base::Type9, VISITOR_REF>(visitor);
      } break;
      case 10: {
        applyImp<typename Base::Type10, VISITOR_REF>(visitor);
      } break;
      case 11: {
        applyImp<typename Base::Type11, VISITOR_REF>(visitor);
      } break;
      case 12: {
        applyImp<typename Base::Type12, VISITOR_REF>(visitor);
      } break;
      case 13: {
        applyImp<typename Base::Type13, VISITOR_REF>(visitor);
      } break;
      case 14: {
        applyImp<typename Base::Type14, VISITOR_REF>(visitor);
      } break;
      case 15: {
        applyImp<typename Base::Type15, VISITOR_REF>(visitor);
      } break;
      case 16: {
        applyImp<typename Base::Type16, VISITOR_REF>(visitor);
      } break;
      case 17: {
        applyImp<typename Base::Type17, VISITOR_REF>(visitor);
      } break;
      case 18: {
        applyImp<typename Base::Type18, VISITOR_REF>(visitor);
      } break;
      case 19: {
        applyImp<typename Base::Type19, VISITOR_REF>(visitor);
      } break;
      case 20: {
        applyImp<typename Base::Type20, VISITOR_REF>(visitor);
      } break;
      default: {
        BSLS_ASSERT_INVOKE_NORETURN("Unreachable by design!");
      } break;
    }
}

template <class TYPES>
template <class VISITOR_REF, class RET_TYPE>
RET_TYPE VariantImp<TYPES>::doApplyR(VISITOR_REF visitor, int type) const
{
    switch (type) {
      case 0: {
        BSLS_ASSERT_INVOKE_NORETURN("'doApplyR' invoked on an unset variant");
      } break;
      case 1: {
        return applyImpR<typename Base::Type1,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 2: {
        return applyImpR<typename Base::Type2,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 3: {
        return applyImpR<typename Base::Type3,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 4: {
        return applyImpR<typename Base::Type4,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 5: {
        return applyImpR<typename Base::Type5,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 6: {
        return applyImpR<typename Base::Type6,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 7: {
        return applyImpR<typename Base::Type7,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 8: {
        return applyImpR<typename Base::Type8,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 9: {
        return applyImpR<typename Base::Type9,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 10: {
        return applyImpR<typename Base::Type10,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 11: {
        return applyImpR<typename Base::Type11,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 12: {
        return applyImpR<typename Base::Type12,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 13: {
        return applyImpR<typename Base::Type13,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 14: {
        return applyImpR<typename Base::Type14,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 15: {
        return applyImpR<typename Base::Type15,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 16: {
        return applyImpR<typename Base::Type16,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 17: {
        return applyImpR<typename Base::Type17,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 18: {
        return applyImpR<typename Base::Type18,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 19: {
        return applyImpR<typename Base::Type19,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      case 20: {
        return applyImpR<typename Base::Type20,
                         VISITOR_REF,
                         RET_TYPE>(visitor);                          // RETURN
      } break;
      default: {
        BSLS_ASSERT_INVOKE_NORETURN("Unreachable by design!");
      } break;
    }
}

// CREATORS
template <class TYPES>
inline
VariantImp<TYPES>::VariantImp()
: Base(0, 0)
{
}

template <class TYPES>
template <class TYPE_OR_ALLOCATOR>
inline
VariantImp<TYPES>::VariantImp(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Base(Variant_TypeIndex<TYPES, TYPE_OR_ALLOCATOR>::value,
       valueOrAllocator,
       bsl::integral_constant<bool, bsl::is_convertible<TYPE_OR_ALLOCATOR,
                                                 bslma::Allocator *>::value>())
{
    enum {
        k_IS_ALLOCATOR = bsl::is_convertible<TYPE_OR_ALLOCATOR,
                                             bslma::Allocator *>::value
    };

    create(valueOrAllocator, bsl::integral_constant<bool, k_IS_ALLOCATOR>());
}

template <class TYPES>
template <class TYPE>
inline
VariantImp<TYPES>::VariantImp(const TYPE&       value,
                              bslma::Allocator *basicAllocator)
: Base(Variant_TypeIndex<TYPES, TYPE>::value, basicAllocator)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     value);
}

template <class TYPES>
template <class TYPE>
VariantImp<TYPES>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
VariantImp(TYPE&&                   value,
           typename bsl::enable_if<
               !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
               &&
               !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                       void>::type *)
#else
VariantImp(bslmf::MovableRef<TYPE>  value)
#endif
: Base(Variant_TypeIndex<
                     TYPES,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
       0)
{
    typedef bsls::ObjectBuffer<
                 typename bsl::remove_const<
                 typename bsl::remove_reference<TYPE>::type>::type> BufferType;

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    bslma::ConstructionUtil::construct(
                 reinterpret_cast<BufferType *>(&this->d_value)->address(),
                 this->getAllocator(),
                 BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    bslma::ConstructionUtil::construct(
                 reinterpret_cast<BufferType *>(&this->d_value)->address(),
                 this->getAllocator(),
                 bslmf::MovableRefUtil::move(lvalue));
#endif
}

template <class TYPES>
template <class TYPE>
VariantImp<TYPES>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
VariantImp(TYPE&&                   value,
           typename bsl::enable_if<
               !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
           bslma::Allocator>::type *basicAllocator)
#else
VariantImp(bslmf::MovableRef<TYPE>  value,
           bslma::Allocator        *basicAllocator)
#endif
: Base(Variant_TypeIndex<
                     TYPES,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
       basicAllocator)
{
    typedef bsls::ObjectBuffer<
                 typename bsl::remove_const<
                 typename bsl::remove_reference<TYPE>::type>::type> BufferType;

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    bslma::ConstructionUtil::construct(
                     reinterpret_cast<BufferType *>(&this->d_value)->address(),
                     this->getAllocator(),
                     bslmf::MovableRefUtil::move(lvalue));
#endif
}

template <class TYPES>
VariantImp<TYPES>::VariantImp(const VariantImp&  original,
                              bslma::Allocator  *basicAllocator)
: Base(original.d_type, basicAllocator)
{
    if (this->d_type) {
        Variant_CopyConstructVisitor copyConstructor(&this->d_value,
                                                     this->getAllocator());
        original.apply(copyConstructor);
    }
}

template <class TYPES>
VariantImp<TYPES>::VariantImp(bslmf::MovableRef<VariantImp> original)
: Base(MoveUtil::access(original).d_type,
       MoveUtil::access(original).getAllocator())
{
    if (this->d_type) {
        Variant_MoveConstructVisitor moveConstructor(&this->d_value,
                                                     this->getAllocator());
        VariantImp& lvalue = original;

        lvalue.apply(moveConstructor);
    }
}

template <class TYPES>
VariantImp<TYPES>::VariantImp(bslmf::MovableRef<VariantImp>  original,
                              bslma::Allocator              *basicAllocator)
: Base(MoveUtil::access(original).d_type, basicAllocator)
{
    if (this->d_type) {
        Variant_MoveConstructVisitor moveConstructor(&this->d_value,
                                                     this->getAllocator());
        VariantImp& lvalue = original;

        lvalue.apply(moveConstructor);
    }
}

template <class TYPES>
inline
VariantImp<TYPES>::~VariantImp()
{
    reset();
}

// MANIPULATORS
template <class TYPES>
template <class TYPE>
inline
VariantImp<TYPES>&
VariantImp<TYPES>::operator=(const TYPE& value)
{
    return assign(value);
}

template <class TYPES>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<VariantImp<TYPES>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
VariantImp<TYPES> >::type&
VariantImp<TYPES>::operator=(TYPE&&                  value)
#else
VariantImp<TYPES>&
VariantImp<TYPES>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    return assign(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    return assign(MoveUtil::move(lvalue));
#endif
}

template <class TYPES>
VariantImp<TYPES>&
VariantImp<TYPES>::operator=(const VariantImp& rhs)
{
    if (&rhs != this) {
        if (this->d_type == rhs.d_type) {
            if (this->d_type) {
                Variant_CopyAssignVisitor assigner(&this->d_value);
                rhs.apply(assigner);
            }
        }
        else {
            reset();
            if (rhs.d_type) {
                Variant_CopyConstructVisitor copyConstructor(
                                                         &this->d_value,
                                                         this->getAllocator());
                rhs.apply(copyConstructor);
                this->d_type = rhs.d_type;
            }
        }
    }

    return *this;
}

template <class TYPES>
VariantImp<TYPES>&
VariantImp<TYPES>::operator=(bslmf::MovableRef<VariantImp> rhs)
{
    VariantImp& lvalue = rhs;

    if (&lvalue != this) {
        if (this->d_type == lvalue.d_type) {
            if (this->d_type) {
                Variant_MoveAssignVisitor assigner(&this->d_value);
                lvalue.apply(assigner);
            }
        }
        else {
            reset();
            if (lvalue.d_type) {
                Variant_MoveConstructVisitor moveConstructor(
                                                         &this->d_value,
                                                         this->getAllocator());
                lvalue.apply(moveConstructor);
                this->d_type = lvalue.d_type;
            }
        }
    }

    return *this;
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::apply(VISITOR& visitor)
{
    if (this->d_type) {
        return doApplyR<VISITOR&, RET_TYPE>(visitor, this->d_type);   // RETURN
    }

    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::apply(const VISITOR& visitor)
{
    if (this->d_type) {
        return doApplyR<const VISITOR&, RET_TYPE>(visitor, this->d_type);
                                                                      // RETURN
    }

    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR, class TYPE>
inline
RET_TYPE VariantImp<TYPES>::apply(VISITOR& visitor, const TYPE& defaultValue)
{
    if (this->d_type) {
        return doApplyR<VISITOR&, RET_TYPE>(visitor, this->d_type);   // RETURN
    }

    return visitor(defaultValue);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR, class TYPE>
inline
RET_TYPE VariantImp<TYPES>::apply(const VISITOR& visitor,
                                  const TYPE&    defaultValue)
{
    if (this->d_type) {
        return doApplyR<const VISITOR&, RET_TYPE>(visitor, this->d_type);
                                                                      // RETURN
    }

    return visitor(defaultValue);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::applyRaw(VISITOR& visitor)
{
    typedef Variant_RawVisitorHelper<RET_TYPE, VISITOR> Helper;

    return doApplyR<const Helper&, RET_TYPE>(Helper(&visitor), this->d_type);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::applyRaw(const VISITOR& visitor)
{
    typedef Variant_RawVisitorHelper<RET_TYPE, const VISITOR> Helper;

    return doApplyR<const Helper&, RET_TYPE>(Helper(&visitor), this->d_type);
}

template <class TYPES>
template <class TYPE>
VariantImp<TYPES>& VariantImp<TYPES>::assign(const TYPE& value)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    if (Variant_TypeIndex<TYPES, TYPE>::value == this->d_type) {
        reinterpret_cast<BufferType *>(&this->d_value)->object() = value;
    }
    else {
        assignImp<TYPE, TYPE>(value);
    }

    return *this;
}

template <class TYPES>
template <class TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
VariantImp<TYPES>& VariantImp<TYPES>::assign(TYPE&&                  value)
#else
VariantImp<TYPES>& VariantImp<TYPES>::assign(bslmf::MovableRef<TYPE> value)
#endif
{
    typedef bsls::ObjectBuffer<typename bsl::remove_reference<TYPE>::type>
                                                                    BufferType;

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    if (Variant_TypeIndex<TYPES,
                          typename bsl::remove_reference<TYPE>::type>::value
                                                             == this->d_type) {
        reinterpret_cast<BufferType *>(&this->d_value)->object() =
                                    BSLS_COMPILERFEATURES_FORWARD(TYPE, value);
    }
    else {
        assignImp<TYPE>(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
    }
#else
    TYPE& lvalue = value;

    if (Variant_TypeIndex<TYPES, TYPE>::value == this->d_type) {
        reinterpret_cast<BufferType *>(&this->d_value)->object() =
                                                        MoveUtil::move(lvalue);
    }
    else {
        assignImp<TYPE>(MoveUtil::move(lvalue));
    }
#endif

    return *this;
}

template <class TYPES>
template <class TYPE, class SOURCE_TYPE>
VariantImp<TYPES>& VariantImp<TYPES>::assignTo(const SOURCE_TYPE& value)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;

    if (Variant_TypeIndex<TYPES, TYPE>::value == this->d_type
     && bsl::is_same<TYPE, SOURCE_TYPE>::value) {
        reinterpret_cast<BufferType *>(&this->d_value)->object() = value;
    }
    else {
        assignImp<TYPE, SOURCE_TYPE>(value);
    }

    return *this;
}

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_variant.h
#ifndef BDLB_VARIANT_VARIADIC_LIMIT
#define BDLB_VARIANT_VARIADIC_LIMIT 14
#endif
#ifndef BDLB_VARIANT_VARIADIC_LIMIT_B
#define BDLB_VARIANT_VARIADIC_LIMIT_B BDLB_VARIANT_VARIADIC_LIMIT
#endif

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 0
template <class TYPES>
template <class TYPE>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                          )
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator());
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 0

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 1
template <class TYPES>
template <class TYPE, class ARGS_01>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 1

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 2
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 2

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 3
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 3

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 4
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 4

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 5
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 5

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 6
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 6

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 7
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 7

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 8
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 8

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 9
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 9

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 10
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09,
                      class ARGS_10>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_10, arguments_10));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 10

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 11
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09,
                      class ARGS_10,
                      class ARGS_11>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_10, arguments_10),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_11, arguments_11));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 11

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 12
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09,
                      class ARGS_10,
                      class ARGS_11,
                      class ARGS_12>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_10, arguments_10),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_11, arguments_11),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_12, arguments_12));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 12

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 13
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09,
                      class ARGS_10,
                      class ARGS_11,
                      class ARGS_12,
                      class ARGS_13>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_13) arguments_13)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_10, arguments_10),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_11, arguments_11),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_12, arguments_12),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_13, arguments_13));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 13

#if BDLB_VARIANT_VARIADIC_LIMIT_B >= 14
template <class TYPES>
template <class TYPE, class ARGS_01,
                      class ARGS_02,
                      class ARGS_03,
                      class ARGS_04,
                      class ARGS_05,
                      class ARGS_06,
                      class ARGS_07,
                      class ARGS_08,
                      class ARGS_09,
                      class ARGS_10,
                      class ARGS_11,
                      class ARGS_12,
                      class ARGS_13,
                      class ARGS_14>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_10) arguments_10,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_11) arguments_11,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_12) arguments_12,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_13) arguments_13,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_14) arguments_14)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_01, arguments_01),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_02, arguments_02),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_03, arguments_03),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_04, arguments_04),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_05, arguments_05),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_06, arguments_06),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_07, arguments_07),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_08, arguments_08),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_09, arguments_09),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_10, arguments_10),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_11, arguments_11),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_12, arguments_12),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_13, arguments_13),
                         BSLS_COMPILERFEATURES_FORWARD(ARGS_14, arguments_14));
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}
#endif  // BDLB_VARIANT_VARIADIC_LIMIT_B >= 14

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.

template <class TYPES>
template <class TYPE, class... ARGS>
inline
TYPE& VariantImp<TYPES>::createInPlace(
                          BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)... arguments)
{
    typedef bsls::ObjectBuffer<TYPE> BufferType;
    BufferType& bufR = *reinterpret_cast<BufferType *>(&this->d_value);

    reset();
    bslma::ConstructionUtil::construct(
                            bufR.address(),
                            this->getAllocator(),
                            BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
    this->d_type = Variant_TypeIndex<TYPES, TYPE>::value;

    return bufR.object();
}

// }}} END GENERATED CODE
#endif

template <class TYPES>
void VariantImp<TYPES>::reset()
{
    if (this->d_type) {
        Variant_DestructorVisitor destructor;
        apply(destructor);
        this->d_type = 0;
    }
}

template <class TYPES>
void VariantImp<TYPES>::swap(VariantImp<TYPES>& other)
{
    if (!this->d_type) {
        if (!other.d_type) {
            return;                                                   // RETURN
        }
        *this = other;
        other.reset();
    }
    else if (!other.d_type) {
        other = *this;
        this->reset();
    }
    else {
        if (this->d_type         == other.d_type
         && this->getAllocator() == other.getAllocator()) {
            // Same types and same allocators, so use a visitor that calls
            // 'swap'.

            Variant_SwapVisitor swapper(&this->d_value);
            other.apply(swapper);
        }
        else {
            // Different types and/or allocators, so swap via assignment.  Note
            // that this doesn't fit the usual pattern for calling 'swap'
            // because infinite recursion would result.

            bsl::swap(*this, other);
        }
    }
}

template <class TYPES>
template <class TYPE>
inline
TYPE& VariantImp<TYPES>::the()
{
    BSLMF_ASSERT((0 != Variant_TypeIndex<TYPES, TYPE>::value));
    BSLS_ASSERT_SAFE((this->d_type == Variant_TypeIndex<TYPES, TYPE>::value));

    typedef bsls::ObjectBuffer<TYPE> BufferType;

    return reinterpret_cast<BufferType *>(&this->d_value)->object();
}

// ACCESSORS
template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::apply(VISITOR& visitor) const
{
    if (this->d_type) {
        return doApplyR<VISITOR&, RET_TYPE>(visitor, this->d_type);   // RETURN
    }

    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::apply(const VISITOR& visitor) const
{
    if (this->d_type) {
        return doApplyR<const VISITOR&, RET_TYPE>(visitor, this->d_type);
                                                                      // RETURN
    }

    bslmf::Nil nil = bslmf::Nil();
    return visitor(nil);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR, class TYPE>
inline
RET_TYPE VariantImp<TYPES>::apply(VISITOR&    visitor,
                                  const TYPE& defaultValue) const
{
    if (this->d_type) {
        return doApplyR<VISITOR&, RET_TYPE>(visitor, this->d_type);   // RETURN
    }

    return visitor(defaultValue);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR, class TYPE>
inline
RET_TYPE VariantImp<TYPES>::apply(const VISITOR& visitor,
                                  const TYPE&    defaultValue) const
{
    if (this->d_type) {
        return doApplyR<const VISITOR&, RET_TYPE>(visitor, this->d_type);
                                                                      // RETURN
    }

    return visitor(defaultValue);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::applyRaw(VISITOR& visitor) const
{
    typedef Variant_RawVisitorHelper<RET_TYPE, VISITOR> Helper;

    return doApplyR<const Helper&, RET_TYPE>(Helper(&visitor), this->d_type);
}

template <class TYPES>
template <class RET_TYPE, class VISITOR>
inline
RET_TYPE VariantImp<TYPES>::applyRaw(const VISITOR& visitor) const
{
    typedef Variant_RawVisitorHelper<RET_TYPE, const VISITOR> Helper;

    return doApplyR<const Helper&, RET_TYPE>(Helper(&visitor), this->d_type);
}

template <class TYPES>
template <class TYPE>
inline
bool VariantImp<TYPES>::is() const
{
    return Variant_TypeIndex<TYPES, TYPE>::value == this->d_type;
}

template <class TYPES>
inline
bool VariantImp<TYPES>::isUnset() const
{
    return !this->d_type;
}

template <class TYPES>
bsl::ostream&
VariantImp<TYPES>::print(bsl::ostream& stream,
                         int           level,
                         int           spacesPerLevel) const
{
    if (this->d_type) {
        Variant_PrintVisitor visitor(&stream, level, spacesPerLevel);

        doApply<const Variant_PrintVisitor&>(visitor, this->d_type);
    }
    return stream;
}

template <class TYPES>
template <class TYPE>
inline
const TYPE& VariantImp<TYPES>::the() const
{
    BSLMF_ASSERT((0 != Variant_TypeIndex<TYPES, TYPE>::value));
    BSLS_ASSERT_SAFE((this->d_type == Variant_TypeIndex<TYPES, TYPE>::value));

    typedef bsls::ObjectBuffer<TYPE> BufferType;

    return reinterpret_cast<const BufferType *>(&this->d_value)->object();
}

template <class TYPES>
inline
int VariantImp<TYPES>::typeIndex() const
{
    return this->d_type;
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
template <class TYPES>
inline
const bsl::type_info& VariantImp<TYPES>::typeInfo() const
{
    return typeid(void);
}

template <class TYPES>
template <class STREAM>
STREAM& VariantImp<TYPES>::bdexStreamIn(STREAM& stream, int version)
{
    int type;
    bslx::InStreamFunctions::bdexStreamIn(stream, type, 0);

    if (!stream || type < 0 || 20 < type) {
        stream.invalidate();
        return stream;
    }

    if (type != this->d_type) {
        reset();

        if (type) {
            Variant_DefaultConstructVisitor defaultConstructor(
                                                         this->getAllocator());
            doApply(defaultConstructor, type);
        }

        this->d_type = type;
    }

    if (type) {
        Variant_BdexStreamInVisitor<STREAM> streamer(stream, version);
        doApply(streamer, type);
    }
    return stream;
}

template <class TYPES>
inline
int VariantImp<TYPES>::maxSupportedBdexVersion() const
{
    return 1;
}

template <class TYPES>
template <class STREAM>
STREAM& VariantImp<TYPES>::bdexStreamOut(STREAM& stream, int version) const
{
    bslx::OutStreamFunctions::bdexStreamOut(stream, this->d_type, 0);

    if (this->d_type) {
        typedef Variant_BdexStreamOutVisitor<STREAM> Streamer;

        Streamer streamer(stream, version);
        doApply<Streamer&>(streamer, this->d_type);
    }
    return stream;
}

#endif  // BDE_OMIT_INTERNAL_DEPRECATED

}  // close package namespace

// FREE OPERATORS
template <class TYPES>
bool bdlb::operator==(const VariantImp<TYPES>& lhs,
                      const VariantImp<TYPES>& rhs)
{
    if (lhs.typeIndex() != rhs.typeIndex()) {
        return false;                                                 // RETURN
    }

    if (0 == lhs.typeIndex()) {
        return true;                                                  // RETURN
    }

    Variant_EqualityTestVisitor visitor(&rhs.d_value);
    lhs.apply(visitor);

    return visitor.d_result;
}

template <class TYPES>
inline
bool bdlb::operator!=(const VariantImp<TYPES>& lhs,
                      const VariantImp<TYPES>& rhs)
{
    return !(lhs == rhs);
}

template <class TYPES>
inline
bsl::ostream& bdlb::operator<<(bsl::ostream&            stream,
                               const VariantImp<TYPES>& object)
{
    return object.print(stream, 0, -1);
}

// FREE FUNCTIONS
template <class TYPES>
inline
void bdlb::swap(VariantImp<TYPES>& a, VariantImp<TYPES>& b)
{
    a.swap(b);
}

namespace bdlb {

                       // ------------------
                       // class Variant<...>
                       // ------------------

// CREATORS
#if defined(BDLB_VARIANT_USING_VARIADIC_TEMPLATES)
template <class ...TYPES>
inline
Variant<TYPES...>::Variant()
{
}

template <class ...TYPES>
template <class TYPE_OR_ALLOCATOR>
inline
Variant<TYPES...>::Variant(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class ...TYPES>
template <class TYPE>
inline
Variant<TYPES...>::Variant(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class ...TYPES>
template <class TYPE>
inline
Variant<TYPES...>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant(TYPE&&                   value,
        typename bsl::enable_if<
            !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
            &&
            !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                    void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class ...TYPES>
template <class TYPE>
inline
Variant<TYPES...>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant(TYPE&&                   value,
        typename bsl::enable_if<
            !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
        bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant(bslmf::MovableRef<TYPE>  value,
        bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

/// Up-cast needed since template matching has higher overloading precedence
/// than derived-to-base matching.
template <class ...TYPES>
inline
Variant<TYPES...>::Variant(const Variant&    original,
                           bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class ...TYPES>
inline
Variant<TYPES...>::Variant(bslmf::MovableRef<Variant> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class ...TYPES>
inline
Variant<TYPES...>::Variant(bslmf::MovableRef<Variant>  original,
                           bslma::Allocator           *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class ...TYPES>
template <class TYPE>
inline
Variant<TYPES...>& Variant<TYPES...>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class ...TYPES>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant<TYPES...>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant<TYPES...> >::type&
Variant<TYPES...>::operator=(TYPE&&                  value)
#else
Variant<TYPES...>&
Variant<TYPES...>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class ...TYPES>
inline
Variant<TYPES...>& Variant<TYPES...>::operator=(const Variant& rhs)
{
    // Up-cast needed since template matching has higher overloading precedence
    // than derived-to-base matching.

    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class ...TYPES>
inline
Variant<TYPES...>& Variant<TYPES...>::operator=(bslmf::MovableRef<Variant> rhs)
{
    // Up-cast needed since template matching has higher overloading precedence
    // than derived-to-base matching.

    Variant& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

#else  // BDLB_VARIANT_USING_VARIADIC_TEMPLATES
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant()
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE_OR_ALLOCATOR>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant(
                                     const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant(
                                              const TYPE&       value,
                                              bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant(TYPE&&                   value,
        typename bsl::enable_if<
            !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
            &&
            !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                    void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant(TYPE&&                   value,
        typename bsl::enable_if<
            !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
        bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant(bslmf::MovableRef<TYPE>  value,
        bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant(
                                              const Variant&    original,
                                              bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
    // Up-cast needed since template matching has higher overloading precedence
    // than derived-to-base matching.
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant(
                                           bslmf::MovableRef<Variant> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::Variant(
                                    bslmf::MovableRef<Variant>  original,
                                    bslma::Allocator           *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>&
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,
                          A8,  A9,  A10, A11, A12, A13, A14,
                          A15, A16, A17, A18, A19, A20>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
        A16, A17, A18, A19, A20> >::type&
Variant<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
        A16, A17, A18, A19, A20>::operator=(TYPE&&                  value)
#else
Variant<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
        A16, A17, A18, A19, A20>&
Variant<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
        A16, A17, A18, A19, A20>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>&
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::operator=(const Variant& rhs)
{
    // Up-cast needed since template matching has higher overloading precedence
    // than derived-to-base matching.

    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19, class A20>
inline
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>&
Variant<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10, A11, A12,
        A13, A14, A15, A16, A17, A18, A19, A20>::
operator=(bslmf::MovableRef<Variant> rhs)
{
    // Up-cast needed since template matching has higher overloading precedence
    // than derived-to-base matching.

    Variant& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

#endif  // BDLB_VARIANT_USING_VARIADIC_TEMPLATES

#ifdef BDLB_VARIANT_USING_VARIADIC_TEMPLATES
#undef BDLB_VARIANT_USING_VARIADIC_TEMPLATES
#endif

                       // -------------------
                       // class Variant2<...>
                       // -------------------

// CREATORS
template <class A1, class A2>
inline
Variant2<A1, A2>::Variant2()
{
}

template <class A1, class A2>
template <class TYPE_OR_ALLOCATOR>
inline
Variant2<A1, A2>::Variant2(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2>
template <class TYPE>
inline
Variant2<A1, A2>::Variant2(const TYPE&       value,
                           bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2>
template <class TYPE>
inline
Variant2<A1, A2>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant2(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant2(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2>
template <class TYPE>
inline
Variant2<A1, A2>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant2(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant2(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2>
inline
Variant2<A1, A2>::Variant2(const Variant2&   original,
                           bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2>
inline
Variant2<A1, A2>::Variant2(bslmf::MovableRef<Variant2> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2>
inline
Variant2<A1, A2>::Variant2(bslmf::MovableRef<Variant2>  original,
                           bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2>
template <class TYPE>
inline
Variant2<A1, A2>&
Variant2<A1, A2>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant2<A1, A2>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant2<A1, A2> >::type&
Variant2<A1, A2>::operator=(TYPE&&                  value)
#else
Variant2<A1, A2>&
Variant2<A1, A2>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2>
inline
Variant2<A1, A2>&
Variant2<A1, A2>::operator=(const Variant2& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2>
inline
Variant2<A1, A2>&
Variant2<A1, A2>::operator=(bslmf::MovableRef<Variant2> rhs)
{
    Variant2& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant3<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>::Variant3()
{
}

template <class A1, class A2, class A3>
template <class TYPE_OR_ALLOCATOR>
inline
Variant3<A1, A2, A3>::
Variant3(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3>
template <class TYPE>
inline
Variant3<A1, A2, A3>::
Variant3(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3>
template <class TYPE>
inline
Variant3<A1, A2, A3>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant3(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant3(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3>
template <class TYPE>
inline
Variant3<A1, A2, A3>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant3(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
        bslma::Allocator>::type  *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant3(bslmf::MovableRef<TYPE>  value,
        bslma::Allocator         *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>::
Variant3(const Variant3& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>::
Variant3(bslmf::MovableRef<Variant3> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>::
Variant3(bslmf::MovableRef<Variant3>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3>
template <class TYPE>
inline
Variant3<A1, A2, A3>&
Variant3<A1, A2, A3>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant3<A1, A2, A3>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant3<A1, A2, A3> >::type&
Variant3<A1, A2, A3>::operator=(TYPE&&                  value)
#else
Variant3<A1, A2, A3>&
Variant3<A1, A2, A3>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>&
Variant3<A1, A2, A3>::operator=(const Variant3& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3>
inline
Variant3<A1, A2, A3>&
Variant3<A1, A2, A3>::operator=(bslmf::MovableRef<Variant3> rhs)
{
    Variant3& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant4<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>::Variant4()
{
}

template <class A1, class A2, class A3, class A4>
template <class TYPE_OR_ALLOCATOR>
inline
Variant4<A1, A2, A3, A4>::
Variant4(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4>
template <class TYPE>
inline
Variant4<A1, A2, A3, A4>::
Variant4(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4>
template <class TYPE>
inline
Variant4<A1, A2, A3, A4>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant4(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant4(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4>
template <class TYPE>
inline
Variant4<A1, A2, A3, A4>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant4(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant4(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>::
Variant4(const Variant4& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>::
Variant4(bslmf::MovableRef<Variant4> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>::
Variant4(bslmf::MovableRef<Variant4>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4>
template <class TYPE>
inline
Variant4<A1, A2, A3, A4>&
Variant4<A1, A2, A3, A4>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant4<A1, A2, A3, A4>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant4<A1, A2, A3, A4> >::type&
Variant4<A1, A2, A3, A4>::operator=(TYPE&&                  value)
#else
Variant4<A1, A2, A3, A4>&
Variant4<A1, A2, A3, A4>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>&
Variant4<A1, A2, A3, A4>::operator=(const Variant4& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4>
inline
Variant4<A1, A2, A3, A4>&
Variant4<A1, A2, A3, A4>::operator=(bslmf::MovableRef<Variant4> rhs)
{
    Variant4& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant5<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>::Variant5()
{
}

template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE_OR_ALLOCATOR>
inline
Variant5<A1, A2, A3, A4, A5>::
Variant5(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE>
inline
Variant5<A1, A2, A3, A4, A5>::
Variant5(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE>
inline
Variant5<A1, A2, A3, A4, A5>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant5(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant5(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE>
inline
Variant5<A1, A2, A3, A4, A5>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant5(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant5(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>::
Variant5(const Variant5& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>::
Variant5(bslmf::MovableRef<Variant5> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>::
Variant5(bslmf::MovableRef<Variant5>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE>
inline
Variant5<A1, A2, A3, A4, A5>&
Variant5<A1, A2, A3, A4, A5>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant5<A1, A2, A3, A4, A5>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant5<A1, A2, A3, A4, A5> >::type&
Variant5<A1, A2, A3, A4, A5>::operator=(TYPE&&                  value)
#else
Variant5<A1, A2, A3, A4, A5>&
Variant5<A1, A2, A3, A4, A5>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>&
Variant5<A1, A2, A3, A4, A5>::operator=(const Variant5& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5>
inline
Variant5<A1, A2, A3, A4, A5>&
Variant5<A1, A2, A3, A4, A5>::operator=(bslmf::MovableRef<Variant5> rhs)
{
    Variant5& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant6<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>::Variant6()
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE_OR_ALLOCATOR>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
Variant6(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
Variant6(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant6(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant6(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant6(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant6(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
Variant6(const Variant6& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
Variant6(bslmf::MovableRef<Variant6> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>::
Variant6(bslmf::MovableRef<Variant6>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE>
inline
Variant6<A1, A2, A3, A4, A5, A6>&
Variant6<A1, A2, A3, A4, A5, A6>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant6<A1, A2, A3, A4, A5, A6>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant6<A1, A2, A3, A4, A5, A6> >::type&
Variant6<A1, A2, A3, A4, A5, A6>::operator=(TYPE&&                  value)
#else
Variant6<A1, A2, A3, A4, A5, A6>&
Variant6<A1, A2, A3, A4, A5, A6>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>&
Variant6<A1, A2, A3, A4, A5, A6>::operator=(const Variant6& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6>
inline
Variant6<A1, A2, A3, A4, A5, A6>&
Variant6<A1, A2, A3, A4, A5, A6>::operator=(bslmf::MovableRef<Variant6> rhs)
{
    Variant6& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant7<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::Variant7()
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE_OR_ALLOCATOR>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
Variant7(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
Variant7(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant7(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant7(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant7(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant7(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
Variant7(const Variant7& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
Variant7(bslmf::MovableRef<Variant7> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>::
Variant7(bslmf::MovableRef<Variant7>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>&
Variant7<A1, A2, A3, A4, A5, A6, A7>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant7<A1, A2, A3, A4, A5, A6, A7>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant7<A1, A2, A3, A4, A5, A6, A7> >::type&
Variant7<A1, A2, A3, A4, A5, A6, A7>::operator=(TYPE&&                  value)
#else
Variant7<A1, A2, A3, A4, A5, A6, A7>&
Variant7<A1, A2, A3, A4, A5, A6, A7>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>&
Variant7<A1, A2, A3, A4, A5, A6, A7>::
operator=(const Variant7& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline
Variant7<A1, A2, A3, A4, A5, A6, A7>&
Variant7<A1, A2, A3, A4, A5, A6, A7>::
operator=(bslmf::MovableRef<Variant7> rhs)
{
    Variant7& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant8<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::Variant8()
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE_OR_ALLOCATOR>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
Variant8(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
Variant8(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant8(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant8(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant8(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant8(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
Variant8(const Variant8& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
Variant8(bslmf::MovableRef<Variant8> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
Variant8(bslmf::MovableRef<Variant8>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>&
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant8<A1, A2, A3, A4, A5, A6, A7, A8>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant8<A1, A2, A3, A4, A5, A6, A7, A8> >::type&
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
operator=(TYPE&&                  value)
#else
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>&
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>&
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
operator=(const Variant8& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8>
inline
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>&
Variant8<A1, A2, A3, A4, A5, A6, A7, A8>::
operator=(bslmf::MovableRef<Variant8> rhs)
{
    Variant8& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // -------------------
                       // class Variant9<...>
                       // -------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::Variant9()
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE_OR_ALLOCATOR>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
Variant9(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
Variant9(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant9(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
             &&
             !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                     void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant9(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant9(TYPE&&                   value,
         typename bsl::enable_if<
             !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
         bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant9(bslmf::MovableRef<TYPE>  value,
         bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
Variant9(const Variant9& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
Variant9(bslmf::MovableRef<Variant9> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
Variant9(bslmf::MovableRef<Variant9>  original,
         bslma::Allocator            *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>&
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9> >::type&
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
operator=(TYPE&&                  value)
#else
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>&
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>&
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
operator=(const Variant9& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9>
inline
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>&
Variant9<A1, A2, A3, A4, A5, A6, A7, A8, A9>::
operator=(bslmf::MovableRef<Variant9> rhs)
{
    Variant9& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant10<...>
                       // --------------------

// CREATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::Variant10()
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE_OR_ALLOCATOR>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
Variant10(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
Variant10(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant10(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant10(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant10(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant10(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
Variant10(const Variant10& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
Variant10(bslmf::MovableRef<Variant10> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
Variant10(bslmf::MovableRef<Variant10>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>&
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> >::type&
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
operator=(TYPE&&                  value)
#else
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>&
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>&
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
operator=(const Variant10& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4, class A5, class A6, class A7,
          class A8, class A9, class A10>
inline
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>&
Variant10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::
operator=(bslmf::MovableRef<Variant10> rhs)
{
    Variant10& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant11<...>
                       // --------------------

// CREATORS
template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11()
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE_OR_ALLOCATOR>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant11(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant11(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant11(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant11(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11(const Variant11& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11(bslmf::MovableRef<Variant11> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
Variant11(bslmf::MovableRef<Variant11>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>&
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11> >::type&
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
operator=(TYPE&&                  value)
#else
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>&
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>&
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
operator=(const Variant11& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5, class A6,
          class A7, class A8, class A9, class A10, class A11>
inline
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>&
Variant11<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::
operator=(bslmf::MovableRef<Variant11> rhs)
{
    Variant11& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant12<...>
                       // --------------------

// CREATORS
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12()
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE_OR_ALLOCATOR>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant12(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant12(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant12(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant12(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12(const Variant12& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12(bslmf::MovableRef<Variant12> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
Variant12(bslmf::MovableRef<Variant12>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>&
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12> >::type&
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
operator=(TYPE&&                  value)
#else
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>&
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>&
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
operator=(const Variant12& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12>
inline
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>&
Variant12<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>::
operator=(bslmf::MovableRef<Variant12> rhs)
{
    Variant12& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant13<...>
                       // --------------------

// CREATORS
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13()
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE_OR_ALLOCATOR>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant13(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant13(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant13(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant13(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13(const Variant13& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13(bslmf::MovableRef<Variant13> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
Variant13(bslmf::MovableRef<Variant13>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>&
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12,
                            A13>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13> >::type&
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
operator=(TYPE&&                  value)
#else
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>&
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>&
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
operator=(const Variant13& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1, class A2, class A3, class A4,  class A5,  class A6,
          class A7, class A8, class A9, class A10, class A11, class A12,
          class A13>
inline
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>&
Variant13<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>::
operator=(bslmf::MovableRef<Variant13> rhs)
{
    Variant13& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant14<...>
                       // --------------------

// CREATORS
template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14()
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE_OR_ALLOCATOR>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant14(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant14(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant14(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant14(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14(const Variant14& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14(bslmf::MovableRef<Variant14> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
Variant14(bslmf::MovableRef<Variant14>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>&
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant14<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12,
                            A13, A14>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14> >::type&
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
operator=(TYPE&&                  value)
#else
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>&
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>&
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
operator=(const Variant14& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2, class A3, class A4,  class A5,  class A6,
          class A7,  class A8, class A9, class A10, class A11, class A12,
          class A13, class A14>
inline
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>&
Variant14<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14>::
operator=(bslmf::MovableRef<Variant14> rhs)
{
    Variant14& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant15<...>
                       // --------------------

// CREATORS
template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15()
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE_OR_ALLOCATOR>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant15(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant15(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant15(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant15(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15(const Variant15& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15(bslmf::MovableRef<Variant15> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
Variant15(bslmf::MovableRef<Variant15>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>&
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant15<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11,
                            A12, A13, A14, A15>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15> >::type&
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
operator=(TYPE&&                  value)
#else
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>&
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>&
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
operator=(const Variant15& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3, class A4,  class A5,  class A6,
          class A7,  class A8,  class A9, class A10, class A11, class A12,
          class A13, class A14, class A15>
inline
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>&
Variant15<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15>::
operator=(bslmf::MovableRef<Variant15> rhs)
{
    Variant15& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant16<...>
                       // --------------------

// CREATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16()
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE_OR_ALLOCATOR>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant16(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant16(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant16(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant16(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16(const Variant16& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16(bslmf::MovableRef<Variant16> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
Variant16(bslmf::MovableRef<Variant16>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>&
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant16<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11,
                            A12, A13, A14, A15, A16>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant16<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16> >::type&
Variant16<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16>::operator=(TYPE&&                  value)
#else
Variant16<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16>&
Variant16<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>&
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
operator=(const Variant16& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16>
inline
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>&
Variant16<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16>::
operator=(bslmf::MovableRef<Variant16> rhs)
{
    Variant16& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant17<...>
                       // --------------------

// CREATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17()
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE_OR_ALLOCATOR>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant17(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant17(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant17(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant17(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17(const Variant17& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17(bslmf::MovableRef<Variant17> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
Variant17(bslmf::MovableRef<Variant17>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>&
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant17<A1,  A2,  A3,  A4,  A5,  A6, A7, A8, A9, A10, A11,
                            A12, A13, A14, A15, A16, A17>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant17<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17> >::type&
Variant17<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17>::operator=(TYPE&&                  value)
#else
Variant17<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17>&
Variant17<A1,  A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>&
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
operator=(const Variant17& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17>
inline
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>&
Variant17<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17>::
operator=(bslmf::MovableRef<Variant17> rhs)
{
    Variant17& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant18<...>
                       // --------------------

// CREATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18()
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE_OR_ALLOCATOR>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant18(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant18(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant18(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant18(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18(const Variant18& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18(bslmf::MovableRef<Variant18> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
Variant18(bslmf::MovableRef<Variant18>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>&
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant18<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8, A9, A10,
                            A11, A12, A13, A14, A15, A16, A17, A18>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant18<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18> >::type&
Variant18<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18>::operator=(TYPE&&                  value)
#else
Variant18<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18>&
Variant18<A1,  A2,  A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>&
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
operator=(const Variant18& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18>
inline
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>&
Variant18<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18>::
operator=(bslmf::MovableRef<Variant18> rhs)
{
    Variant18& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

                       // --------------------
                       // class Variant19<...>
                       // --------------------

// CREATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19()
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE_OR_ALLOCATOR>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19(const TYPE_OR_ALLOCATOR& valueOrAllocator)
: Imp(valueOrAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19(const TYPE& value, bslma::Allocator *basicAllocator)
: Imp(value, basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant19(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                      SelfType,
                      typename bsl::remove_const<
                      typename bsl::remove_reference<TYPE>::type>::type>::value
              &&
              !bsl::is_convertible<TYPE, bslma::Allocator *>::value,
                      void>::type *)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value))
#else
Variant19(bslmf::MovableRef<TYPE>  value)
: Imp(MoveUtil::move(value))
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
Variant19(TYPE&&                   value,
          typename bsl::enable_if<
              !bsl::is_same<
                     SelfType,
                     typename bsl::remove_const<
                     typename bsl::remove_reference<TYPE>::type>::type>::value,
          bslma::Allocator>::type *basicAllocator)
: Imp(BSLS_COMPILERFEATURES_FORWARD(TYPE, value), basicAllocator)
#else
Variant19(bslmf::MovableRef<TYPE>  value,
          bslma::Allocator        *basicAllocator)
: Imp(MoveUtil::move(value), basicAllocator)
#endif
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19(const Variant19& original, bslma::Allocator *basicAllocator)
: Imp(static_cast<const Imp&>(original), basicAllocator)
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19(bslmf::MovableRef<Variant19> original)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))))
{
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
Variant19(bslmf::MovableRef<Variant19>  original,
          bslma::Allocator             *basicAllocator)
: Imp(MoveUtil::move(static_cast<Imp&>(MoveUtil::access(original))),
      basicAllocator)
{
}

// MANIPULATORS
template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>&
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
operator=(const TYPE& value)
{
    Imp::operator=(value);
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
template <class TYPE>
inline
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
typename bsl::enable_if<
    !bsl::is_same<Variant19<A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8,  A9, A10,
                            A11, A12, A13, A14, A15, A16, A17, A18, A19>,
                  typename bsl::remove_cvref<TYPE>::type>::value,
Variant19<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18, A19> >::type&
Variant19<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18, A19>::operator=(TYPE&&                  value)
#else
Variant19<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18, A19>&
Variant19<A1,  A2,  A3,  A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
          A16, A17, A18, A19>::operator=(bslmf::MovableRef<TYPE> value)
#endif
{
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    Imp::operator=(BSLS_COMPILERFEATURES_FORWARD(TYPE, value));
#else
    TYPE& lvalue = value;
    Imp::operator=(MoveUtil::move(lvalue));
#endif

    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>&
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
operator=(const Variant19& rhs)
{
    Imp::operator=(static_cast<const Imp&>(rhs));
    return *this;
}

template <class A1,  class A2,  class A3,  class A4,  class A5,  class A6,
          class A7,  class A8,  class A9,  class A10, class A11, class A12,
          class A13, class A14, class A15, class A16, class A17, class A18,
          class A19>
inline
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>&
Variant19<A1,  A2,  A3,  A4,  A5, A6, A7, A8, A9, A10, A11, A12, A13, A14,
          A15, A16, A17, A18, A19>::
operator=(bslmf::MovableRef<Variant19> rhs)
{
    Variant19& lvalue = rhs;

    Imp::operator=(MoveUtil::move(static_cast<Imp&>(lvalue)));
    return *this;
}

}  // close package namespace
}  // close enterprise namespace

#else // if ! defined(DEFINED_BDLB_VARIANT_H)
# error Not valid except when included from bdlb_variant.h
#endif // ! defined(COMPILING_BDLB_VARIANT_H)

#endif // ! defined(INCLUDED_BDLB_VARIANT_CPP03)

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
