// bslmf_isconvertible.h                                              -*-C++-*-
#ifndef INCLUDED_BSLMF_ISCONVERTIBLE
#define INCLUDED_BSLMF_ISCONVERTIBLE

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a compile-time check for type conversion.
//
//@CLASSES:
//  bsl::is_convertible: standard meta-function for type conversion checking
//  bsl::is_convertible_v: the result value of 'bsl::is_convertible'
//  bslmf::IsConvertible: meta-function for type conversion checking
//
//@SEE_ALSO: bslmf_integralconstant
//
//@DESCRIPTION: This component defines two meta-functions,
// 'bsl::is_convertible' and 'BloombergLP::bslmf::IsConvertible' and a template
// variable 'bsl::is_convertible_v', that represents the result value of the
// 'bsl::is_convertible' meta-function.  All these meta-functions may be used
// to check whether an implicit conversion exists from one type to another.
//
// 'bsl::is_convertible' meets the requirements of the 'is_convertible'
// template defined in the C++11 standard [meta.rel], while
// 'bslmf::IsConvertible' was devised before 'is_convertible' was standardized.
//
// The two meta-functions are functionally equivalent except that
// 'bsl::is_convertible' does not allow its template parameter types to be
// incomplete types according to the C++11 standard while
// 'bslmf::IsConvertible' tests conversions involving incomplete types.  The
// other major difference between them is that the result for
// 'bsl::is_convertible' is indicated by the class members 'value' and 'type',
// whereas the result for 'bslmf::IsConvertible' is indicated by the class
// members 'VALUE' and 'Type'.
//
// Note that 'bsl::is_convertible' should be preferred over
// 'bslmf::IsConvertible', and in general, should be used by new components.
// Also note that 'bsl::is_convertible' and 'bslmf::IsConvertible' can produce
// compiler errors if the conversion is ambiguous.  For example:
//..
//  struct A {};
//  struct B : public A {};
//  struct C : public A {};
//  struct D : public B, public C {};
//
//  static int const C = bsl::is_convertible<D*, A*>::value;  // ERROR!
//..
// Also note that the template variable 'is_convertible_v' is defined in the
// C++17 standard as an inline variable.  If the current compiler supports the
// inline variable C++17 compiler feature, 'bsl::is_convertible_v' is defined
// as an 'inline constexpr bool' variable.  Otherwise, if the compiler supports
// the variable templates C++14 compiler feature, 'bsl::is_convertible_v' is
// defined as a non-inline 'constexpr bool' variable.  See
// 'BSLS_COMPILERFEATURES_SUPPORT_INLINE_VARIABLES' and
// 'BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES' macros in
// bsls_compilerfeatures component for details.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Select Function Based on Type Convertibility
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The 'bsl::is_convertible' meta-function can be used to select an appropriate
// function (at compile time) based on the convertibility of one type to
// another without causing a compiler error by actually trying the conversion.
//
// First, we define two classes, 'Foo' and 'Bar'.  The 'Foo' class has an
// explict constructor from 'int', an implicit conversion operator that returns
// an integer value while the 'Bar' class does neither:
//..
//  class Foo {
//      // DATA
//      int d_value;
//
//    public:
//      // CREATORS
//      explicit Foo(int value) : d_value(value) {}
//
//      // ACCESSORS
//      operator int() const { return d_value; }
//  };
//
//  class Bar {};
//..
// Then, we run:
//..
//  assert(false == (bsl::is_convertible<int, Foo>::value));
//  assert(false == (bsl::is_convertible<int, Bar>::value));
//
//  assert(true  == (bsl::is_convertible<Foo, int>::value));
//  assert(false == (bsl::is_convertible<Bar, int>::value));
//..
// Note that 'int' to 'Foo' is false, even though 'Foo' has a constructor that
// takes an 'int'.  This is because that constructor is explicit, and
// 'is_converitble' ignores explicit constructors.
//
// Next, we go on to demonstrate how this could be used.  Suppose we are
// implementing a 'convertToInt' template method that converts a given object
// of the (template parameter) 't_TYPE' to 'int' type, and returns the integer
// value.  If the given object can not convert to 'int', return 0.  The method
// calls an overloaded function, 'getIntValue', to get the converted integer
// value.  The idea is to invoke one version of 'getIntValue' if the type
// provides a conversion operator that returns an integer value, and another
// version if the type does not provide such an operator.
//
// We define the first 'getIntValue' function that takes a 'bsl::false_type' as
// its last argument, whereas the second 'getIntValue' function takes a
// 'bsl::true_type' object.  The result of the 'bsl::is_convertible'
// meta-function (i.e., its 'type' member) is used to create the last argument
// passed to 'getIntValue'.  Neither version of 'getIntValue' makes use of this
// argument -- it is used only to differentiate the argument list so we can
// overload the function.
//..
//  template <class t_TYPE>
//  inline
//  int getIntValue(t_TYPE *, bsl::false_type)
//  {
//      // Return 0 because the specified 't_TYPE' is not convertible to the
//      // 'int' type.
//
//      return 0;
//  }
//
//  template <class t_TYPE>
//  inline
//  int getIntValue(t_TYPE *object, bsl::true_type)
//  {
//      // Return the integer value converted from the specified 'object' of
//      // the (template parameter) 't_TYPE'.
//
//      return int(*object);
//  }
//..
// Now, we define our 'convertToInt' method:
//..
//  template <class t_TYPE>
//  inline
//  int convertToInt(t_TYPE *object)
//  {
//      typedef typename bsl::is_convertible<t_TYPE,
//                                           int>::type CanConvertToInt;
//      return getIntValue(object, CanConvertToInt());
//  }
//..
// Notice that we use 'bsl::is_convertible' to get a 'bsl::false_type' or
// 'bsl::true_type', and then call the corresponding overloaded 'getIntValue'
// method.
//
// Finally, we call our finished product and observe the return values:
//..
//  Foo foo(99);
//  Bar bar;
//
//  assert(99 == convertToInt(&foo));
//  assert(0  == convertToInt(&bar));
//..

#include <bslscm_version.h>

#include <bslmf_addconst.h>
#include <bslmf_addlvaluereference.h>
#include <bslmf_assert.h>
#include <bslmf_conditional.h>
#include <bslmf_enableif.h>
#include <bslmf_integralconstant.h>
#include <bslmf_isarray.h>
#include <bslmf_isfunction.h>
#include <bslmf_isfundamental.h>
#include <bslmf_ispointer.h>
#include <bslmf_isvoid.h>
#include <bslmf_matchanytype.h>
#include <bslmf_removecv.h>

#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_platform.h>

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
# include <type_traits>
#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#if defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)
# if !defined(BSLS_PLATFORM_CMP_MSVC) || BSLS_PLATFORM_CMP_VERSION > 1900
    // The Microsoft implementation of native traits allows binding of rvalues
    // (including temporaries invented for conversion) to 'const volatile &'
    // references.  Early versions also do not correctly disallow conversion
    // from itself for types that are neither copy- nor move-constructible.
#   define BSLMF_ISCONVERTIBLE_USE_NATIVE_TRAITS
# endif
#endif

namespace bsl {

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible;

#ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES
template <class t_FROM_TYPE, class t_TO_TYPE>
BSLS_KEYWORD_INLINE_VARIABLE constexpr bool is_convertible_v =
                                 is_convertible<t_FROM_TYPE, t_TO_TYPE>::value;
    // This template variable represents the result value of the
    // 'bsl::is_convertible' meta-function.
#endif

}  // close namespace bsl

namespace BloombergLP {
namespace bslmf {

                 // =========================================
                 // private class IsConvertible_CheckComplete
                 // =========================================

template <class t_TYPE,
          bool = bsl::is_function<t_TYPE>::value ||
                 bsl::is_void<t_TYPE>::value>
struct IsConvertible_CheckComplete {
    typedef t_TYPE type;

    enum { k_CHECK_COMPLETE = sizeof(t_TYPE) };
};

template <class t_TYPE>
struct IsConvertible_CheckComplete<t_TYPE&, false>
: IsConvertible_CheckComplete<t_TYPE> {
    typedef t_TYPE&  type;
};

#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
template <class t_TYPE>
struct IsConvertible_CheckComplete<t_TYPE&&, false>
: IsConvertible_CheckComplete<t_TYPE> {
    typedef t_TYPE && type;
};
#endif

template <class t_TYPE>
struct IsConvertible_CheckComplete<t_TYPE, true> {
    typedef t_TYPE type;
};

#if !defined(BSLS_PLATFORM_CMP_IBM)  // IBM rejects this valid specialization
template <class t_TYPE>
struct IsConvertible_CheckComplete<t_TYPE[], false> {
    typedef t_TYPE type[];
};
#endif

}  // close package namespace
}  // close enterprise namespace

#ifdef BSLMF_ISCONVERTIBLE_USE_NATIVE_TRAITS

namespace bsl {

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible
: ::bsl::integral_constant<
      bool,
      ::std::is_convertible<
          typename BloombergLP::bslmf::IsConvertible_CheckComplete<
              t_FROM_TYPE>::type,
          typename BloombergLP::bslmf::IsConvertible_CheckComplete<
              t_TO_TYPE>::type>::value> {
};

}  // close namespace bsl
#else

namespace BloombergLP {
namespace bslmf {

                         // ==========================
                         // struct IsConvertible_Match
                         // ==========================

struct IsConvertible_Match {
    // This 'struct' provides functions to check for successful conversion
    // matches.  Sun CC 5.2 requires that this 'struct' not be nested within
    // 'IsConvertible_Imp'.

    typedef struct { char a;    } yes_type;
    typedef struct { char a[2]; } no_type;

    static yes_type match(IsConvertible_Match&);
        // Return 'yes_type' if called on 'IsConvertible_Match' type.

#if !defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
    template <class t_TYPE>
    static no_type match(const t_TYPE&);
        // Return 'yes_type' if the (template parameter) 't_TYPE' is
        // 'IsConvertible_Match', and 'no_type' otherwise.

    template <class t_TYPE>
    static no_type match(const volatile t_TYPE&);
        // Return 'yes_type' if the (template parameter) 't_TYPE' is
        // 'IsConvertible_Match' and 'no_type' otherwise.

    template <class t_TYPE>
    static typename
    bsl::enable_if<bsl::is_function<t_TYPE>::value, no_type>::type
    match(t_TYPE&);
        // Return 'yes_type' if the (template parameter) 't_TYPE' is
        // 'IsConvertible_Match' and 'no_type' otherwise.
#else
    template <class t_TYPE>
    static no_type match(t_TYPE&&);
        // Return 'yes_type' if the (template parameter) 't_TYPE' is
        // 'IsConvertible_Match', and 'no_type' otherwise.
#endif
};

                         // ========================
                         // struct IsConvertible_Imp
                         // ========================

template <class t_FROM_TYPE,
          class t_TO_TYPE
#if defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)
          ,
          int IS_FROM_FUNDAMENTAL = bsl::is_fundamental<t_FROM_TYPE>::value,
          int IS_TO_FUNDAMENTAL   = bsl::is_fundamental<t_TO_TYPE>::value
#endif
          >
struct IsConvertible_Imp {
    // This 'struct' template implements the meta-function to determine type
    // conversion between the (template parameter) 't_FROM_TYPE' and the
    // (template parameter) 't_TO_TYPE' where the conversion to the 't_TO_TYPE'
    // is not necessarily the same as conversion to 'const t_TO_TYPE&'.
    //
    // Note that significant documentation about the details of this
    // implementation can be found in 'bslmf_isconvertible.cpp'.

  private:
    struct Test
    {
        // A unique (empty) type returned by the comma operator.

        IsConvertible_Match& operator, (t_TO_TYPE) const;
            // Return a reference to type 'IsConvertible_Match'.
    };

  public:

#ifdef BSLS_PLATFORM_CMP_MSVC
#   pragma warning(push)
#   pragma warning(disable: 4244)  // loss of precision warning ignored
#endif
    enum {

        value = (sizeof(IsConvertible_Match::yes_type) ==
                 sizeof(IsConvertible_Match::match(
                                       (Test(), TypeRep<t_FROM_TYPE>::rep()))))
        // Return the convertibility between 't_FROM_TYPE' and 't_TO_TYPE'.
        // This is set by invoking the 'operator,' method having 'Test&' on
        // the left and 't_FROM_TYPE' on the right.  The 'value' is 'true' if
        // 't_FROM_TYPE' is convertible to 't_TO_TYPE', and 'false' otherwise.
    };

#ifdef BSLS_PLATFORM_CMP_MSVC
#   pragma warning(pop)
#endif

    typedef bsl::integral_constant<bool, value> type;
        // This 'typedef' returns 'bsl::true_type' if 't_FROM_TYPE' is
        // convertible to 't_TO_TYPE', and 'bsl::false_type' otherwise.
};

#if 0 // defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)
// The following template partial specializations produce the same results as
// the unspecialized template would, but avoid generating conversion warnings
// on the affected compilers.  However, there is one known bug in this block of
// code (reported by the test driver, not yet tracked down) and experimentally
// removing it seems to clear the bug, without raising the feared warnings on
// supported gcc platforms - although it still raises a few warnings with gcc
// 4.3.5.

#define BSLMF_ISCONVERTIBLE_SAMETYPEVALUE(t_VALUE,                            \
                                          t_FROM,                             \
                                          t_TO,                               \
                                          t_FROM_FUND,                        \
                                          t_TO_FUND)                          \
    template <class t_TYPE>                                                   \
    struct IsConvertible_Imp<t_FROM, t_TO, t_FROM_FUND, t_TO_FUND>            \
    : bsl::integral_constant<bool, VALUE> {                                   \
    };
    // This partial specialization of 'bslmf::IsConvertible_Imp' derives from
    // 'bsl::integral_constant' having the specified macro argument 'VALUE'.
    // The specified macro arguments 't_FROM' and 't_TO' are cv-qualified type
    // expressions constructed out of the (template parameter) 't_TYPE'.

#define BSLMF_ISCONVERTIBLE_VALUE(t_VALUE,                                    \
                                  t_FROM,                                     \
                                  t_TO,                                       \
                                  t_FROM_FUND,                                \
                                  t_TO_FUND)                                  \
    template <class t_FROM_TYPE, class t_TO_TYPE>                             \
    struct IsConvertible_Imp<t_FROM, t_TO, t_FROM_FUND, t_TO_FUND>            \
    : bsl::integral_constant<bool, t_VALUE> {                                 \
    };
    // This partial specialization of 'bslmf::IsConvertible_Imp' derives from
    // 'bsl::integral_constant' having the specified macro argument 't_VALUE'.
    // The specified macro arguments 't_FROM' and 't_TO' are cv-qualified type
    // expressions constructed out of 't_FROM_TYPE' and 't_TO_TYPE',
    // respectively.

#define BSLMF_ISCONVERTIBLE_FORWARD(t_FROM, t_TO, t_FROM_FUND, t_TO_FUND)     \
    template <class t_FROM_TYPE, class t_TO_TYPE>                             \
    struct IsConvertible_Imp<t_FROM, t_TO, t_FROM_FUND, t_TO_FUND>            \
    : IsConvertible_Imp<t_FROM, t_TO, 0, 0> {                                 \
    };
    // This partial specialization of 'bslmf::IsConvertible_Imp' applies the
    // general mechanism for non-fundamental types.  The specified macro
    // arguments 't_FROM' and 't_TO' are cv-qualified type expressions
    // constructed out of 't_FROM_TYPE' and 't_TO_TYPE', respectively.

BSLMF_ISCONVERTIBLE_SAMETYPEVALUE(0,
                                  const volatile t_TYPE,
                                  const t_TYPE&,
                                  1,
                                  1)
BSLMF_ISCONVERTIBLE_SAMETYPEVALUE(0,
                                  volatile t_TYPE,
                                  const t_TYPE&,
                                  1,
                                  1)
    // These two partial specializations are instantiated when a (possibly
    // 'const'-qualified) 'volatile' fundamental type is tested for
    // convertibility to its 'const' reference type.  The conversion shall
    // fail.

BSLMF_ISCONVERTIBLE_VALUE(1,
                          const volatile t_FROM_TYPE,
                          const t_TO_TYPE&,
                          1,
                          1)
BSLMF_ISCONVERTIBLE_VALUE(1,
                          volatile t_FROM_TYPE,
                          const t_TO_TYPE&,
                          1,
                          1)
    // These two partial specializations are instantiated when a (possibly
    // 'const'-qualified) 'volatile' type is tested for convertibility to the
    // 'const' reference type of another fundamental type.  These partial
    // specializations will be picked up if the previous two fail to match.
    // The conversion shall succeed.

BSLMF_ISCONVERTIBLE_VALUE(1, const t_FROM_TYPE, const t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_VALUE(1,       t_FROM_TYPE, const t_TO_TYPE&, 1, 1)
    // These two partial specializations are instantiated when a (possibly
    // 'const'-qualified) fundamental type is tested for convertibility to the
    // 'const' reference type of another fundamental type.  These partial
    // specializations will be picked up if the previous two fail to match.
    // The conversion shall succeed.

BSLMF_ISCONVERTIBLE_FORWARD(const volatile t_FROM_TYPE,
                            const volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(      volatile t_FROM_TYPE,
                            const volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(const          t_FROM_TYPE,
                            const volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(               t_FROM_TYPE,
                            const volatile t_TO_TYPE&, 1, 1)
    // These four partial specializations are instantiated when a (possibly
    // cv-qualified) fundamental type is tested for convertibility to the
    // 'const volatile' reference type of another fundamental type.

BSLMF_ISCONVERTIBLE_FORWARD(const volatile t_FROM_TYPE,
                                  volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(      volatile t_FROM_TYPE,
                                  volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(const          t_FROM_TYPE,
                                  volatile t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(               t_FROM_TYPE,
                                  volatile t_TO_TYPE&, 1, 1)
    // These four partial specializations are instantiated when a (possibly
    // cv-qualified) fundamental type is tested for convertibility to the
    // 'volatile' reference type of another fundamental type.

BSLMF_ISCONVERTIBLE_FORWARD(const volatile t_FROM_TYPE, t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(      volatile t_FROM_TYPE, t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(const          t_FROM_TYPE, t_TO_TYPE&, 1, 1)
BSLMF_ISCONVERTIBLE_FORWARD(               t_FROM_TYPE, t_TO_TYPE&, 1, 1)
    // These four partial specializations are instantiated when a (possibly
    // cv-qualified) fundamental type is tested for convertibility to the
    // non-cv-qualified reference type of another fundamental type.

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_Imp<const t_FROM_TYPE, t_TO_TYPE, 1, 1>
    : IsConvertible_Imp<const t_FROM_TYPE, double, 0, 0>::type {
    // This partial specialization is instantiated when the 'const' (template
    // parameter) fundamental 't_FROM_TYPE' is tested for convertibility to
    // another (template parameter) fundamental 't_TO_TYPE'.  This partial
    // specialization derives from
    // 'IsConvertible_Imp<const t_FROM_TYPE, double, 0, 0>' to avoid any
    // compilation warnings in case the 't_TO_TYPE' is an integral type and
    // 't_FROM_TYPE' is a floating-point type.
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_Imp<t_FROM_TYPE, t_TO_TYPE, 1, 1>
    : IsConvertible_Imp<t_FROM_TYPE, double, 0, 0>::type {
    // This partial specialization is instantiated when the (template
    // parameter) fundamental 't_FROM_TYPE' is tested for convertibility to
    // another (template parameter) fundamental 't_TO_TYPE'.  This partial
    // specialization derives from
    // 'IsConvertible_Imp<t_FROM_TYPE, double, 0, 0>' to avoid any compilation
    // warnings in case that the 't_FROM_TYPE' is a floating-point type and
    // 't_TO_TYPE' is an integral type.
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_Imp<t_FROM_TYPE, t_TO_TYPE, 0, 1>
    : IsConvertible_Imp<t_FROM_TYPE, double, 0, 0>::type {
    // This partial specialization is instantiated when the (template
    // parameter) 't_FROM_TYPE' is a non-fundamental type, and the (template
    // parameter) 't_TO_TYPE' is a non-'void' fundamental type.  This partial
    // specialization derives from
    // 'IsConvertible_Imp<t_FROM_TYPE, double, 0, 0>' to avoid any compilation
    // warnings in case that the 't_FROM_TYPE' is a floating-point type and the
    // 't_TO_TYPE' is an integral type.
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_Imp<t_FROM_TYPE, t_TO_TYPE, 1, 0>
    : IsConvertible_Imp<int, t_TO_TYPE, 0, 0>::type {
    // This partial specialization is instantiated when the (template
    // parameter) 't_FROM_TYPE' is a non-'void' fundamental type, and the
    // (template parameter) 't_TO_TYPE' is a non-fundamental type.  This
    // partial specialization derives from
    // 'IsConvertible_Imp<int, t_TO_TYPE, 0, 0>' to avoid any compilation
    // warnings in case that the 't_FROM_TYPE' is a floating-point type and the
    // 't_TO_TYPE' is an integral type.
};

#undef BSLMF_ISCONVERTIBLE_SAMETYPEVALUE
#undef BSLMF_ISCONVERTIBLE_VALUE
#undef BSLMF_ISCONVERTIBLE_FORWARD

#endif

template <class t_TO_TYPE>
struct IsConvertible_LazyTrait
: bsl::add_lvalue_reference<typename bsl::add_const<
      typename bsl::remove_cv<t_TO_TYPE>::type>::type> {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_IsNeverConvertible
: bsl::integral_constant<bool,
                         bsl::is_void<t_FROM_TYPE>::value ||
                             bsl::is_array<t_TO_TYPE>::value ||
                             bsl::is_function<t_TO_TYPE>::value> {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_FilterNeverConvertible
: bsl::conditional<
      IsConvertible_IsNeverConvertible<t_FROM_TYPE, t_TO_TYPE>::value,
      bsl::false_type,
      IsConvertible_Imp<t_FROM_TYPE,
                        typename IsConvertible_LazyTrait<t_TO_TYPE>::type> >::
      type {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible_Conditional
: bsl::conditional<
      bsl::is_void<t_TO_TYPE>::value,
      typename bsl::is_void<t_FROM_TYPE>::type,
      IsConvertible_FilterNeverConvertible<
          typename IsConvertible_CheckComplete<t_FROM_TYPE>::type,
          typename IsConvertible_CheckComplete<t_TO_TYPE>::type> >::type {
};

}  // close package namespace
}  // close enterprise namespace

namespace bsl {

                         // ==============================
                         // struct is_convertible_dispatch
                         // ==============================

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch
: BloombergLP::bslmf::IsConvertible_Conditional<t_FROM_TYPE, t_TO_TYPE>::type {
    // This 'struct' template implements the 'is_convertible_dispatch'
    // meta-function defined in the C++11 standard [meta.rel] to determine if
    // the (template parameter) 't_FROM_TYPE' is convertible to the (template
    // parameter) 't_TO_TYPE'.  This 'struct' derives from 'bsl::true_type' if
    // the 't_FROM_TYPE' is convertible to 't_TO_TYPE', and from
    // 'bsl::false_type' otherwise.  Note that both 't_FROM_TYPE' and
    // 't_TO_TYPE' should be complete types, arrays of unknown bound, or
    // (possibly cv-qualified) 'void' types.
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE, t_TYPE&>
: integral_constant<bool,
                    is_reference<t_TYPE>::value ||
                        is_function<t_TYPE>::value ||
                        is_const<t_TYPE>::value> {
    // This set of rules corresponds with the reference binding rules in c++11,
    // where the specification of 'is_convertible_dispatch' relies on
    // rvalue-references.  We must supply these specializations directly in
    // order to support C++03 compilers that do not have a good substitute for
    // rvalue-references, as using 'const &' instead produces subtly different
    // results in some cases.
};

// Some compilers need explicit guidance on a few of the reference-binding
// conversions.  All compilers get most of these correct, but once a few
// specializations are added, the full set is required to avoid ambiguities.

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE, const t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE, volatile t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE, const volatile t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE, const t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE, volatile t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE, const volatile t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE, const t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE, volatile t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE, const volatile t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE, const t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE, volatile t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE, const volatile t_TYPE&>
: false_type {
};

// The next group of partial specializations deal with various cases of
// converting to an lvalue-reference, which we make explicitly conform to the
// C++11 idiom of converting from an rvalue (which may be an lvalue-reference).

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE&, t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE&, const t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE&, volatile t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<t_TYPE&, const volatile t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE&, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE&, const t_TYPE&> : true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE&, volatile t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const t_TYPE&, const volatile t_TYPE&>
: true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE&, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE&, const t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE&, volatile t_TYPE&>
: true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE&, const volatile t_TYPE&>
: true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE&, t_TYPE&> : false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE&, const t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE&, volatile t_TYPE&>
: false_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<const volatile t_TYPE&, const volatile t_TYPE&>
: true_type {
};

template <class t_TYPE>
struct is_convertible_dispatch<volatile t_TYPE, t_TYPE>
: BloombergLP::bslmf::IsConvertible_Conditional<t_TYPE, t_TYPE>::type {
    // Correct handling of non-fundamental volatile conversions to self.  Note
    // that this is not trivially true, but tests that 't_TYPE' is copy (or
    // move) constructible.
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch<t_FROM_TYPE, volatile t_TO_TYPE&> : false_type {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch<t_FROM_TYPE, const volatile t_TO_TYPE&>
: false_type {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch<volatile t_FROM_TYPE&, volatile t_TO_TYPE&>
: is_convertible_dispatch<t_FROM_TYPE *, t_TO_TYPE *>::type {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch<volatile t_FROM_TYPE&,
                               const volatile t_TO_TYPE&>
: is_convertible_dispatch<t_FROM_TYPE, const volatile t_TO_TYPE&>::type {
};

                         // =====================
                         // struct is_convertible
                         // =====================

template <class t_FROM_TYPE>
struct EffectiveFromType : conditional<is_fundamental<t_FROM_TYPE>::value ||
                                           is_pointer<t_FROM_TYPE>::value,
                                       typename remove_cv<t_FROM_TYPE>::type,
                                       t_FROM_TYPE> {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible_dispatch<volatile t_FROM_TYPE&, t_TO_TYPE>
: bsl::conditional<
      bsl::is_fundamental<t_FROM_TYPE>::value,
      typename bsl::is_convertible_dispatch<t_FROM_TYPE, t_TO_TYPE>::type,
      typename BloombergLP::bslmf::IsConvertible_Conditional<
          volatile t_FROM_TYPE,
          t_TO_TYPE>::type>::type {
};

template <class t_FROM_TYPE, class t_TO_TYPE>
struct is_convertible
: is_convertible_dispatch<typename EffectiveFromType<t_FROM_TYPE>::type,
                          t_TO_TYPE>::type {
    // This 'struct' template implements the 'is_convertible_dispatch'
    // meta-function defined in the C++11 standard [meta.rel] to determine if
    // the (template parameter) 't_FROM_TYPE' is convertible to the (template
    // parameter) 't_TO_TYPE'.  This 'struct' derives from 'bsl::true_type' if
    // the 't_FROM_TYPE' is convertible to 't_TO_TYPE', and from
    // 'bsl::false_type' otherwise.  Note that both 't_FROM_TYPE' and
    // 't_TO_TYPE' should be complete types, arrays of unknown bound, or
    // (possibly cv-qualified) 'void' types.
};

}  // close namespace bsl
#endif

namespace BloombergLP {
namespace bslmf {

                         // ====================
                         // struct IsConvertible
                         // ====================

template <class t_FROM_TYPE, class t_TO_TYPE>
struct IsConvertible : bsl::is_convertible<t_FROM_TYPE, t_TO_TYPE>::type {
    // This 'struct' template implements a meta-function to determine if the
    // (template parameter) 't_FROM_TYPE' is convertible to the (template
    // parameter) 't_TO_TYPE'.  This 'struct' derives from 'bsl::true_type' if
    // the 't_FROM_TYPE' is convertible to 't_TO_TYPE', and from
    // 'bsl::false_type' otherwise.  Note that both 't_FROM_TYPE' and
    // 't_TO_TYPE' should be complete types, arrays of unknown bound, or
    // (possibly cv-qualified) 'void' types.
};

}  // close package namespace

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslmf_IsConvertible
#undef bslmf_IsConvertible
#endif
#define bslmf_IsConvertible bslmf::IsConvertible
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif // ! defined(INCLUDED_BSLMF_ISCONVERTIBLE)

// ----------------------------------------------------------------------------
// Copyright 2013 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 ----------------------------------