// bslalg_typetraits.h -*-C++-*- #ifndef INCLUDED_BSLALG_TYPETRAITS #define INCLUDED_BSLALG_TYPETRAITS #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide compile-time traits that can be associated with types. // //@DEPRECATED: Use 'bslmf_nestedtraitdeclaration' instead. // //@CLASSES: // bslalg::TypeTraitNil: nil type trait (no traits) // bslalg::TypeTraitBitwiseMoveable: bitwise-moveable trait // bslalg::TypeTraitBitwiseCopyable: bitwise-copyable trait // bslalg::TypeTraitBitwiseEqualityComparable: bitwise-eq.-comparable trait // bslalg::TypeTraitHasPointerSemantics: dereferences like a pointer // bslalg::TypeTraitHasStlIterators: has STL-like iterators // bslalg::TypeTraitHasTrivialDefaultConstructor: has trivial default ctor // bslalg::TypeTraitPair: for 'std::pair'-like classes // bslalg::TypeTraitUsesBslmaAllocator: uses 'bslma' allocators // //@MACROS: // BSLALG_DECLARE_NESTED_TRAITS: declares a trait in a nested fashion // BSLALG_DECLARE_NESTED_TRAITS2: declares two traits in a nested fashion // BSLALG_DECLARE_NESTED_TRAITS3: declares three traits in a nested fashion // BSLALG_DECLARE_NESTED_TRAITS4: declares four traits in a nested fashion // BSLALG_DECLARE_NESTED_TRAITS5: declares five traits in a nested fashion // //@SEE_ALSO: bslalg_constructorproxy, bslalg_scalarprimitives // //@DESCRIPTION: This component provides a set of type traits, and a set of // macros used to assign traits to user-defined classes. Traits are used to // enable certain optimizations or discriminations at compile-time. For // instance, a class having the trait 'bslalg::TypeTraitBitwiseMoveable' may // allow resizing an array of objects by simply calling 'std::memcpy' instead // of invoking a copy-constructor on every object. The usage example shows // how to use the 'bslalg::TypeTraitUsesBslmaAllocator' to propagate allocators // to nested objects that may require them. // // This component should be used in conjunction with other components from the // package 'bslalg'. See the package-level documentation for an overview. The // most useful classes and macros defined in this component are: //.. // Entity Description // ------ ----------- // bslalg::TypeTraitBitwiseMoveable (See the corresponding class-level // bslalg::TypeTraitBitwiseCopyable documentation.) // bslalg::TypeTraitBitwiseEqualityComparable // bslalg::TypeTraitHasStlIterators // bslalg::TypeTraitHasTrivialDefaultConstructor // bslalg::TypeTraitPair // bslalg::TypeTraitUsesBslmaAllocator // // BSLALG_DECLARE_NESTED_TRAITS(TYPE, TRAIT) A macro to attach a given 'TRAIT' // to a given type 'T' in a nested // fashion. This macro must be used // within the 'public' section of a // class body. // // bslalg::HasTrait<TYPE, TRAIT> This meta-function computes // whether the parameterized 'TYPE' // possesses the parameterized // 'TRAIT'. // // bslalg::SelectTrait<T, TRAIT1, ...> This meta-function selects the // first trait possessed by the // parameterized 'TYPE' from the // ordered list 'TRAIT1', .... //.. // ///Usage ///----- // In this usage example, we show how to enable the 'bslma' allocator model for // generic containers, by implementing simplified versions of the // 'bslalg_constructorproxy' and 'bslalg_scalarprimitives' components. The // interested reader should refer to the documentation of those components. // ///A Generic Container ///- - - - - - - - - - // Suppose we want to implement a generic container of a parameterized 'TYPE', // which may or may not follow the 'bslma' allocator model. If it does, our // container should pass an extra 'bslma::Allocator*' argument to copy // construct a value; but if it does not, then passing this extra argument is // going to generate a compile-time error. It thus appears we need two // implementations of our container. This can be done more succinctly by // encapsulating into the constructor some utilities that will, through a // single interface, determine whether 'TYPE' has the trait // 'bslalg::TypeTraitUsesBslmaAllocator' and copy-construct it accordingly. // // The container contains a single data member of the parameterized 'TYPE'. // Since we are going to initialize this data member manually, we do not want // it to be automatically constructed by the compiler. For this reason, we // encapsulate it in a 'bsls::ObjectBuffer'. //.. // // my_genericcontainer.hpp -*-C++-*- // // template <class TYPE> // class MyGenericContainer { // // This generic container type contains a single object, always // // initialized, which can be replaced and accessed. This container // // always takes an allocator argument and thus follows the // // 'bslalg::TypeTraitUsesBslmaAllocator' protocol. // // // PRIVATE DATA MEMBERS // bsls::ObjectBuffer<TYPE> d_object; //.. // Since the container offers a uniform interface that always takes an extra // allocator argument, regardless of whether 'TYPE' does or not, we can declare // it to have the 'bslalg::TypeTraitUsesBslmaAllocator' trait: //.. // public: // // TRAITS // BSLALG_DECLARE_NESTED_TRAITS(MyGenericContainer, // bslalg::TypeTraitUsesBslmaAllocator); //.. // For simplicity, we let the container contain only a single element, and // require that an element always be initialized. //.. // // CREATORS // explicit MyGenericContainer(const TYPE& object, // bslma::Allocator *allocator = 0); // // Create a container containing the specified 'object', using the // // optionally specified 'allocator' to supply memory. If 'allocator' // // is 0, the currently installed allocator is used. // // MyGenericContainer(const MyGenericContainer& container, // bslma::Allocator *allocator = 0); // // Create a container containing the same object as the specified // // 'container', using the optionally specified 'allocator' to supply // // memory. If 'allocator' is 0, the currently installed allocator is // // used. // // ~MyGenericContainer(); // // Destroy this container. //.. // We can also allow the container to change the object it contains, by // granting modifiable as well as non-modifiable access to this object: //.. // // MANIPULATORS // TYPE& object(); // // // ACCESSORS // const TYPE& object() const; // }; //.. // ///Using the Type Traits ///- - - - - - - - - - - // The challenge in the implementation lies in using the traits of the // contained 'TYPE' to determine whether to pass the allocator argument to its // copy constructor. We rely here on a property of templates that templates // are not compiled (and thus will not generate compilation errors) until they // are instantiated. Hence, we can use two function templates, and let the // overloading resolution (based on the nested traits) decide which to // instantiate. The generic way to create an object, passing through all // arguments (value and allocator) is as follows. For brevity and to avoid // breaking the flow of this example, we have embedded the function definition // into the class. //.. // // my_genericcontainer.cpp i -*-C++-*- // // struct my_GenericContainerUtil { // // This 'struct' provides a namespace for utilities implementing the // // allocator pass-through mechanism in a generic container. // // template <class TYPE> // static void copyConstruct(TYPE *location, // const TYPE& value, // bslma::Allocator *allocator, // bslalg::TypeTraitUsesBslmaAllocator) // // Create a copy of the specified 'value' at the specified // // 'location', using the specified 'allocator' to supply memory. // { // new (location) TYPE(value, allocator); // } //.. // For types that don't use an allocator, we offer the following overload that // will be selected if the type trait of 'TYPE' cannot be converted to // 'bslalg::TypeTraitUsesBslmaAllocator'. In that case, note that the type // traits always inherit from 'bslalg::TypeTraitNil'. //.. // template <class TYPE> // static void copyConstruct(TYPE *location, // const TYPE& value, // bslma::Allocator *allocator, // bslalg::TypeTraitNil) // // Create a copy of the specified 'value' at the specified // // 'location'. Note that the specified 'allocator' is ignored. // { // new (location) TYPE(value); // } //.. // And finally, this function will instantiate the type trait and pass it to // the appropriately (compiler-)chosen overload: //.. // template <class TYPE> // static void copyConstruct(TYPE *location, // const TYPE& value, // bslma::Allocator *allocator) // // Create a copy of the specified 'value' at the specified // // 'location', optionally using the specified 'allocator' to supply // // memory if the parameterized 'TYPE' possesses the // // 'bslalg::TypeTraitUsesBslmaAllocator'. // { // copyConstruct( // location, value, allocator, // typename bsl::conditional< // HasTrait<TYPE, // bslalg::TypeTraitUsesBslmaAllocator>::VALUE, // bslalg::TypeTraitUsesBslmaAllocator, // bslalg::TypeTraitNil>::type()); // } // }; //.. // ///Generic Container Implementation /// - - - - - - - - - - - - - - - - // With these utilities, we can now implement 'MyGenericContainer'. //.. // // CREATORS // template <typename TYPE> // MyGenericContainer<TYPE>::MyGenericContainer(const TYPE& object, // bslma::Allocator *allocator) // { // my_GenericContainerUtil::copyConstruct(&d_object.object(), // object, // allocator); // } // // template <typename TYPE> // MyGenericContainer<TYPE>::MyGenericContainer( // const MyGenericContainer& container, // bslma::Allocator *allocator) // { // my_GenericContainerUtil::copyConstruct(&d_object.object(), // container.object(), // allocator); // } //.. // Note that all this machinery only affects the constructors, and not the // destructor which only invokes the destructor of 'd_object'. //.. // template <typename TYPE> // MyGenericContainer<TYPE>::~MyGenericContainer() // { // (&d_object.object())->~TYPE(); // } //.. // To finish, the accessors and manipulators are trivially implemented. //.. // // MANIPULATORS // template <typename TYPE> // TYPE& MyGenericContainer<TYPE>::object() // { // return d_object.object(); // } // // // ACCESSORS // template <typename TYPE> // const TYPE& MyGenericContainer<TYPE>::object() const // { // return d_object.object(); // } //.. // ///Usage Verification /// - - - - - - - - - // We can check that our container actually forwards the correct allocator to // its contained objects with a very simple test apparatus, consisting of two // classes that have exactly the same signature and implementation except that // one has the 'bslalg::TypeTraitUsesBslmaAllocator' trait and the other does // not: //.. // bslma::Allocator *allocSlot; // // struct MyTestTypeWithBslmaAllocatorTraits { // // Class with declared traits. Calling copy constructor without an // // allocator will compile, but will not set 'allocSlot'. // // // TRAITS // BSLALG_DECLARE_NESTED_TRAITS(MyTestTypeWithBslmaAllocatorTraits, // BloombergLP::bslalg::TypeTraitUsesBslmaAllocator); // // // CREATORS // MyTestTypeWithBslmaAllocatorTraits() {} // // MyTestTypeWithBslmaAllocatorTraits( // const MyTestTypeWithBslmaAllocatorTraits&, // bslma::Allocator *allocator) // { // allocSlot = allocator; // } // }; // // struct MyTestTypeWithNoBslmaAllocatorTraits { // // Class with no declared traits. Calling copy constructor without // // an allocator will not set the 'allocSlot', but passing it by mistake // // will set it. // // // CREATORS // MyTestTypeWithNoBslmaAllocatorTraits() {} // // MyTestTypeWithNoBslmaAllocatorTraits( // const MyTestTypeWithNoBslmaAllocatorTraits &, // bslma::Allocator *allocator) // { // allocSlot = allocator; // } // }; //.. // Our verification program simply instantiates several 'MyGenericContainer' // templates with the two test types above, and checks that the allocator slot // is as expected: //.. // int main() // { // bslma::TestAllocator ta0; // bslma::TestAllocator ta1; //.. // With 'MyTestTypeWithNoBslmaAllocatorTraits', the slot should never be set. //.. // MyTestTypeWithNoBslmaAllocatorTraits x; // // allocSlot = &ta0; // MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x0(x); // assert(&ta0 == allocSlot); // // allocSlot = &ta0; // MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x1(x, &ta1); // assert(&ta0 == allocSlot); //.. // With 'MyTestTypeWithBslmaAllocatorTraits', the slot should be set to the // allocator argument, or to 0 if not specified: //.. // MyTestTypeWithBslmaAllocatorTraits y; // // allocSlot = &ta0; // MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y0(y); // assert(0 == allocSlot); // // allocSlot = &ta0; // MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y1(y, &ta1); // assert(&ta1 == allocSlot); // // return 0; // } //.. #include <bslscm_version.h> #include <bslalg_hastrait.h> #include <bslalg_typetraitbitwisecopyable.h> #include <bslalg_typetraitbitwiseequalitycomparable.h> #include <bslalg_typetraitbitwisemoveable.h> #include <bslalg_typetraithaspointersemantics.h> #include <bslalg_typetraithasstliterators.h> #include <bslalg_typetraithastrivialdefaultconstructor.h> #include <bslalg_typetraitnil.h> #include <bslalg_typetraitpair.h> #include <bslalg_typetraitusesbslmaallocator.h> namespace BloombergLP { // ======================================== // macros BSLALG_DECLARE_NESTED_TRAITS[1-5] // ======================================== #define BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT) \ operator TRAIT::NestedTraitDeclaration<T>() const { \ return TRAIT::NestedTraitDeclaration<T>(); \ } // Associate the specified 'TRAIT' tag with the specified 'T' class. This // macro must be invoked only within the public part of the definition of // class 'T'. 'TRAIT' must name a class such that // 'TRAIT::NestedTraitDeclaration<T>' designates a class derived from // 'bslmf::DetectNestedTrait'. #define BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2) \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2) // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for two traits. #define BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3) \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3) // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for three traits. #define BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4) \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4) // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for four traits. #define BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5) \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4); \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT5) // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for five traits. #ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY // ============================================================================ // BACKWARD COMPATIBILITY // ============================================================================ #ifndef BDE_OMIT_INTERNAL_DEPRECATED #define BDEALG_DECLARE_NESTED_TRAITS(T, TRAITS) \ BSLALG_DECLARE_NESTED_TRAITS(T, TRAITS) // This alias is defined for backward compatibility. #define BDEALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2) \ BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2) // This alias is defined for backward compatibility. #define BDEALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3) \ BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3) // This alias is defined for backward compatibility. #define BDEALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4) \ BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4) // This alias is defined for backward compatibility. #define BDEALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5) \ BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5) // This alias is defined for backward compatibility. #ifdef bdealg_HasTrait #undef bdealg_HasTrait #endif #define bdealg_HasTrait bslalg::HasTrait // This alias is defined for backward compatibility. #ifdef bdealg_SelectTrait #undef bdealg_SelectTrait #endif #define bdealg_SelectTrait bslalg::SelectTrait // This alias is defined for backward compatibility. #endif // BDE_OMIT_INTERNAL_DEPRECATED #endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY } // close enterprise namespace #endif // INCLUDED_BSLALG_TYPETRAITS // ---------------------------------------------------------------------------- // 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 ----------------------------------