// 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: //: o gcc 4.3 or later //: o 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: //: o Compilers with intrinsic support, listed above //: o 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 { template <class t_TYPE> struct is_polymorphic : integral_constant<bool, BloombergLP::bslmf::IsPolymorphic_Imp< typename remove_cv<t_TYPE>::type>::Value> { // 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. }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES template <class t_TYPE> BSLS_KEYWORD_INLINE_VARIABLE constexpr bool is_polymorphic_v = is_polymorphic<t_TYPE>::value; // This template variable represents the result value of the // 'bsl::is_polymorphic' meta-function. #endif } // close namespace bsl namespace BloombergLP { namespace bslmf { // ==================== // struct IsPolymorphic // ==================== template <class t_TYPE> struct IsPolymorphic : bsl::is_polymorphic<t_TYPE>::type { // 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. }; } // close package namespace #ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY // ============================================================================ // BACKWARD COMPATIBILITY // ============================================================================ #ifdef bslmf_IsPolymorphic #undef bslmf_IsPolymorphic #endif #define bslmf_IsPolymorphic bslmf::IsPolymorphic // This alias is defined for backward compatibility. #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 ----------------------------------