// bslmf_ispolymorphic.h                                              -*-C++-*-
#ifndef INCLUDED_BSLMF_ISPOLYMORPHIC
#define INCLUDED_BSLMF_ISPOLYMORPHIC

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

//@PURPOSE: Provide a compile-time check for determining polymorphic types.
//
//@CLASSES:
//  bsl::is_polymorphic: standard meta-function for detecting polymorphic types
//  bsl::is_polymorphic_v: the result value of the meta-function
//  bslmf::IsPolymorphic: meta-function for detecting polymorphic types
//
//@DESCRIPTION: This component defines two meta-functions,
// `bsl::is_polymorphic` and `BloombergLP::bslmf::IsPolymorphic` and a template
// variable `bsl::is_polymorphic_v`, that represents the result value of the
// `bsl::is_polymorphic` meta-function.  All of these meta-functions may be
// used to query whether a type is a polymorphic class as defined in the C++11
// standard [class.virtual].  A class is polymorphic if it has at least one
// virtual function.  Note that the destructor of such a class should *always*
// be declared `virtual`.  Therefore, another definition of polymorphic is
// whether a class has a virtual destructor.
//
// `bsl::is_polymorphic` has the same syntax as the `is_polymorphic` template
// defined in the C++11 standard [meta.unary.prop], while
// `bslmf::IsPolymorphic` was devised before `is_polymorphic` was standardized.
// `bsl::is_polymorphic` meets the requirements of the C++11 standard with two
// exceptions:
//
// 1. The compilation will fail if the meta-function is used to evaluate a
//    `union` type, unless one of the following compilers, which provide an
//    intrinsic operation to detect this specific trait, is used:
//     - gcc 4.3 or later
//     - Visual C++ 2008 or later
// 2. The meta-function will yield false positives, claiming non-polymorphic
//    types *are* polymorphic, for types using virtual inheritance.  This case
//    is known to be handled *correctly* for the following compilers only:
//     - Compilers with intrinsic support, listed above
//     - IBM XLC
//
// The two meta-functions are functionally equivalent.  The major difference
// between them is that the result for `bsl::is_polymorphic` is indicated by
// the class member `value`, while the result for `bslmf::IsPolymorphic` is
// indicated by the class member `value`.  `bsl::is_polymorphic` should be
// preferred over `bslmf::IsPolymorphic`, and in general, should be used by new
// components.
//
// Note that the template variable `is_polymorphic_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_polymorphic_v` is defined as an
// `inline constexpr bool` variable.  Otherwise, if the compiler supports the
// variable templates C++14 compiler feature, `bsl::is_polymorphic_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: Verify Polymorphic Types
///- - - - - - - - - - - - - - - - - -
// Suppose that we want to assert whether a particular type is a polymorphic
// type.
//
// First, we define two types in a non-polymorphic hierarchy, `MyStruct` and
// `MyDerivedStruct`:
// ```
// struct MyStruct {
//     void nonvirtualMethod();
// };
// struct MyDerivedStruct : public MyStruct {
// };
// ```
// Then, we define two types in a polymorphic hierarchy, `MyClass` and
// `MyDerivedClass`:
// ```
// class MyClass {
//   public:
//     MyClass();
//     virtual ~MyClass();  // makes 'MyClass' polymorphic
// };
//
// class MyDerivedClass : public MyClass {
//   public:
//     MyDerivedClass();
//     virtual ~MyDerivedClass();
// };
// ```
// Now, assert that the two types in the non-polymorphic hierarchy are not
// polymorphic, and that the two types in the polymorphic hierarchy are
// polymorphic using `bsl::is_polymorphic`:
// ```
// assert(false == bsl::is_polymorphic<MyStruct          >::value);
// assert(false == bsl::is_polymorphic<MyStruct         *>::value);
// assert(false == bsl::is_polymorphic<MyDerivedStruct&  >::value);
// assert(false == bsl::is_polymorphic<MyDerivedStruct  *>::value);
//
// assert(true  == bsl::is_polymorphic<      MyClass    >::value);
// assert(false == bsl::is_polymorphic<const MyClass&   >::value);
// assert(false == bsl::is_polymorphic<      MyClass   *>::value);
// assert(true  == bsl::is_polymorphic<MyDerivedClass   >::value);
// assert(false == bsl::is_polymorphic<MyDerivedClass&  >::value);
// assert(false == bsl::is_polymorphic<MyDerivedClass  *>::value);
// ```
// Note that if the current compiler supports the variable templates C++14
// feature then we can re-write the snippet of code above using the
// `bsl::is_polymorphic_v` variable as follows:
// ```
// #ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES
//   assert(false == bsl::is_polymorphic_v<MyStruct          >);
//   assert(false == bsl::is_polymorphic_v<MyStruct         *>);
//   assert(false == bsl::is_polymorphic_v<MyDerivedStruct&  >);
//   assert(false == bsl::is_polymorphic_v<MyDerivedStruct  *>);
//
//   assert(true  == bsl::is_polymorphic_v<      MyClass    >);
//   assert(false == bsl::is_polymorphic_v<const MyClass&   >);
//   assert(false == bsl::is_polymorphic_v<      MyClass   *>);
//   assert(true  == bsl::is_polymorphic_v<MyDerivedClass   >);
//   assert(false == bsl::is_polymorphic_v<MyDerivedClass&  >);
//   assert(false == bsl::is_polymorphic_v<MyDerivedClass  *>);
// #endif
// ```

#include <bslscm_version.h>

#include <bslmf_integralconstant.h>
#include <bslmf_isclass.h>
#include <bslmf_removecv.h>

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

#if defined(BSLS_PLATFORM_CMP_CLANG)                                          \
 || defined(BSLS_PLATFORM_CMP_GNU)                                            \
 || defined(BSLS_PLATFORM_CMP_MSVC)                                           \
 || (defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION >= 0x5130)
# define BSLMF_ISPOLYMORPHIC_HAS_INTRINSIC
#endif

namespace BloombergLP {
namespace bslmf {

                       // ========================
                       // struct IsPolymorphic_Imp
                       // ========================

#if defined(BSLMF_ISPOLYMORPHIC_HAS_INTRINSIC)

// Use type traits intrinsic, where available, to give the correct answer for
// the tricky cases where existing ABIs prevent programmatic detection.
template <class t_TYPE>
struct IsPolymorphic_Imp {
    enum { Value = __is_polymorphic(t_TYPE) };
};

#else

template <class t_TYPE, bool t_IS_CLASS = bsl::is_class<t_TYPE>::value>
struct IsPolymorphic_Imp {
    // This 'struct' template provides a meta-function to determine whether the
    // (template parameter) 't_TYPE' is a (non-cv-qualified) polymorphic type.
    // This generic default template defines a static data member, 'Value',
    // that is set to 'false'.  A template specialization is provided (below)
    // to handle the case where 't_TYPE' is a class type that may be
    // polymorphic.

    enum { Value = false };
};

template <class t_TYPE>
struct IsPolymorphic_Imp<t_TYPE, true> {
    // This partial specialization of 'IsPolymorphic_Imp', for when the
    // (template parameter) 't_TYPE' is a (non-cv-qualified) class type,
    // provides a static data member, 'Value', that is set to 'true' if
    // 't_TYPE' is polymorphic and 'false' otherwise.

    struct IsPoly : public t_TYPE {
        IsPoly();
        virtual ~IsPoly() BSLS_NOTHROW_SPEC;

        char dummy[256];
    };

    struct MaybePoly : public t_TYPE {
        MaybePoly();
        ~MaybePoly() BSLS_NOTHROW_SPEC;
        char dummy[256];
    };

    enum { Value = (sizeof(IsPoly) == sizeof(MaybePoly)) };
};

#endif

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

namespace bsl {

/// This `struct` template implements the `is_polymorphic` meta-function
/// defined in the C++11 standard [meta.unary.prop] to determine if the
/// (template parameter) `t_TYPE` is a (possibly cv-qualified) polymorphic
/// type.  This `struct` derives from `bsl::true_type` if the `t_TYPE` is a
/// polymorphic type, and `bsl::false_type` otherwise.
template <class t_TYPE>
struct is_polymorphic
: integral_constant<bool,
                    BloombergLP::bslmf::IsPolymorphic_Imp<
                        typename remove_cv<t_TYPE>::type>::Value> {
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES
/// This template variable represents the result value of the
/// `bsl::is_polymorphic` meta-function.
template <class t_TYPE>
BSLS_KEYWORD_INLINE_VARIABLE constexpr bool is_polymorphic_v =
                                                 is_polymorphic<t_TYPE>::value;
#endif

}  // close namespace bsl

namespace BloombergLP {

namespace bslmf {

                         // ====================
                         // struct IsPolymorphic
                         // ====================

/// This `struct` template implements a meta-function to determine if the
/// (template parameter) `t_TYPE` is a (possibly cv-qualified) polymorphic
/// type.  This `struct` derives from `bsl::true_type` if the `t_TYPE` is a
/// polymorphic type, and `bsl::false_type` otherwise.
///
/// Note that although this `struct` is functionally equivalent to
/// `bsl::is_polymorphic`, the use of `bsl::is_polymorphic` should be
/// preferred.
template <class t_TYPE>
struct IsPolymorphic : bsl::is_polymorphic<t_TYPE>::type {
};

}  // close package namespace

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

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

}  // close enterprise namespace

#endif

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