// bslmf_movableref.h -*-C++-*- #ifndef INCLUDED_BSLMF_MOVABLEREF #define INCLUDED_BSLMF_MOVABLEREF #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a vocabulary type to enable move semantics. // //@CLASSES: // bslmf::MovableRef: a template indicating that an object can be moved from // bslmf::MovableRefUtil: a namespace for functions dealing with movables // //@MACROS: // BSLMF_MOVABLEREF_DEDUCE(t_TYPE): movable ref of 't_TYPE' that is deducible // BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES: defined if MovableRef<T> is 'T&&' // //@SEE_ALSO: // //@DESCRIPTION: This component provides a class template, 'bslmf::MovableRef' // used to convey the information that an object will not be used anymore so // that its representation can be transferred elsewhere. In C++11 terminology // an object represented by a 'bslmf::MovableRef<T>' can be moved from. This // component also provides a utility 'struct' 'bslmf::MovableRefUtil' that // enables use of identical code for C++03 and C++11 to implement move // semantics. // // An object is /movable/ when it isn't being used in a way depending on its // current representation after an operation on this object. For example, when // passing a temporary object to a function the temporary object is movable: it // can't be referred to other than in the function call. When objects are no // longer be used their internal representation can be transferred to another // object. Transferring the internal representation of an object to another // object is called /moving an object/. The purpose of 'bslmf::MovableRef<T>' // is to indicate to a function that an object can be moved to another object. // // With a C++11 implementation 'bslmf::MovableRef<T>' is an alias template for // 'T&&'. With a C++03 implementation 'bslmf::MovableRef<T>' is a class // template providing l-value access to a movable object. The objective of // this component is to provide a name for the concept of a movable object. // Using a common name enables use of manual move semantics when using C++03. // With C++11 additionally automatic move semantics is enabled resulting in // moving objects known to the compiler to go out of scope, e.g., when passing // a temporary object to a function or returning a local variable. // // Using 'bslmf::MovableRef<T>' to support movable types enables the // implementation of move semantics that work with both C++03 and C++11 without // conditional compilation of the user code. Only the implementation of the // component 'bslmf_movableref' uses conditional compilation to select the // appropriate implementation choice. For a C++11 implementation the use of // 'bslmf::MovableRef<T>' instead of 'T&&' has the advantage that the 'T' will // not be deduced an the argument is known to be movable: when a function takes // a 'T&&' as argument with a deduced 'T' the deduced type may be an l-value // reference that isn't necessarily movable. When using 'bslmf::MovableRef<T>' // with C++11 the type will not be deduced and to turn an l-value into a // movable object it is necessary to explicitly use 'move()' at the call site. // // For consistent use across different versions of the C++ standard, a few // utility functions are provided in the utility class 'bslmf::MovableRefUtil'. // This class contains functions for moving and accessing objects. To enable // an identical notation to access an object with C++11 (where // 'bslmf::MovableRef<T>' is just an l-value of type 'T') and with C++03 where // 'bslmf::MovableRef<T>' is a class type referencing an l-value of type 'T', // the function template 'bslmf::MovableRefUtil::access(r)' is provided. // Similarly, the function 'bslmf::MovableRefUtil::move(r)' provides // identical notation for producing a movable reference in both C++03 and // C++11. // // In addition to the 'move' and 'access' functions, the // 'bslmf::MovableRefUtil' namespace provides 7 metafunctions that closely // correspond to similar metafunctions in the C++11 standard library (and // which defer to the standard library where available). These 7 // metafunctions and their C++11 equivalents are shown in the table below: //.. // +-----------------------------+------------------------------+ // | MovableRefUtil trait | C++11 standard trait | // +-----------------------------+------------------------------+ // | IsLvalueReference<t_TYPE> | is_lvalue_reference<t_TYPE> | // | IsMovableReference<t_TYPE> | is_rvalue_reference<t_TYPE> | // | IsReference<t_TYPE> | is_reference<t_TYPE> | // | RemoveReference<t_TYPE> | remove_reference<t_TYPE> | // | AddLvalueReference<t_TYPE> | add_lvalue_reference<t_TYPE> | // | AddMovableReference<t_TYPE> | add_rvalue_reference<t_TYPE> | // | Decay<t_TYPE> | decay<t_TYPE> | // +-----------------------------+------------------------------+ //.. // Note that volatile-qualified 'MovableRef' objects are non-sensical; unlike // const objects they do not occur "naturally" as a result of argument passing // or template-argument deduction and there would be no reason for a program // to create one on purpose. In C++11, moreover, 'volatile MovableRef<T>' is // an alias for 'T&& volatile', which is not a valid type. The traits above, // therefore, will fail to compile when instantiated with a volatile-qualified // 'MovableRef'. Note that, although 'volatile MovableRef<T>' doesn't make // sense, 'MovableRef<volatile T>' is perfectly fine and are equivalent to // 'volatile T&&'. // ///Use of 'MovableRef<t_TYPE>' Parameters ///-------------------------------------- // There are a number of differences how 'MovableRef<t_TYPE>' parameters are // handled between C++03 and C++11 implementations. Due to the language // differences there is no way to avoid these. This component enables use of // move semantics in both C++03 and C++11 when done right. It doesn't try to // make implementation of move semantics easier. Here are some notes to keep // in mind when using this component: // //: 1 When using a 't_TYPE&&' in a context where 't_TYPE' is deduced, the //: resulting reference does normally *not* refer to an object that can be //: moved from! If 'bslmf::MovableRef<t_TYPE>' would deduce the type when //: using a C++11 implementation the name would be rather misleading. Thus, //: the 't_TYPE' won't be deduced. When using a C++03 the type /can/ be //: deduced. However, a program depending on the 't_TYPE' being deduced from //: a 'bslmf::MovableRef<t_TYPE>' will not compile with a C++11 //: implementation. //: //: 2 Returning 'MovableRef<t_TYPE>' (or 't_TYPE&&') from a function is almost //: always wrong. In particular note that the same life-time issues apply to //: 'MovableRef<t_TYPE>' as they do to references of objects: when returning //: a reference the object referred to cannot be on the stack, i.e., //: returning a 'MovableRef<t_TYPE>' referring to a local variable or a //: by-value function parameter is certainly wrong. Returning a //: 'MovableRef<t_TYPE>' to a function parameter received as a reference type //: can be correct. //: //: 3 Using the argument of type 'MovableRef<t_TYPE>' directly in a function //: typically results in incorrect behavior either when using C++03 or when //: using C++11. Instead, use these arguments together with //: 'MovableRefUtil::move()', 'MovableRefUtil::access()', or bind them to a //: non-'const' l-value reference. // // The purpose of 'access(x)' is to use the same notation for member access to // 'x' independent on whether it is an actual l-value reference or an // 'MovableRef<t_TYPE>'. For a concrete examples assume 'x' is a // 'bsl::pair<A, B>'. When using a C++11 implementation // 'MovableRef<bsl::pair<A, B> >' is really just a 'bsl::pair<A, B>&&' and the // elements could be accessed using 'x.first' and 'x.second'. For a C++03 // implementation 'MovableRef<bsl::pair<A, B> >' is a class type and 'x.first' // and 'x.second' are not available. Instead, a reference to the pair needs to // be obtained that could be done using 'static_cast<bsl::pair<A, B >&>(x)' or // by using a named variable. To unify the notation between the C++03 and // C++11 implementation, simultaneously simplifying the C++03 use // 'MovableRefUtil::access(x)' can be used. // ///Template Deduction and Argument Forwarding ///------------------------------------------ // C++11 has two entirely different uses of the notation 'T&&': // //: 1 In contexts where the type 'T' is not deduced 'T&&' indicates an "rvalue //: reference". The notation implies that the resources held by the //: referenced object can be reused, typically because the lifetime of the //: object is about to end. An argument of type 'T&&' can bind to an rvalue //: of type 'T' or to an lvalue of type 'T' that has been explicitly "moved" //: by the caller. //: 2 In contexts where the type 'T' is deduced 'T&&' indicates a "forwarding //: reference. The argument can be either an rvalue or an lvalue and the //: called function can preserve the value category (rvalue or lvalue) when //: forwarding the reference to another function. // // The 'bslmf::MovableRef<T>' emulation of 'T&&' in C++03 works only for rvalue // references, i.e., the first use of the notation. The C++11 definition of // 'bslmf::MovableRef<T>' is designed specifically to avoid deduction of 'T', // thus preventing it from accidentally being used as a forwarding reference // (which would have the wrong effect in C++03). // // For contexts where it is desirable to deduce 'T', the // 'BSLMF_MOVABLEREF_DEDUCE' macro is provided. When invoked like // 'BSLMF_MOVABLEREF_DEDUCE(T)', this macro expands to 'bslmf::MovableRef<T>' // in C++03, and a type alias to 'T&&' for which substitution fails if 'T&&' // would be an lvalue reference in C++11 and later. In both cases, the type // 'T' is deducible, and substitution succeeds only if // 'BSLMF_MOVABLEREF_DEDUCE(T)' deduces a movable reference. // ///Usage ///----- // There are two sides of move semantics: // //: 1 Classes or class templates that are _move-enabled_, i.e., which can //: transfer their internal representation to another object in some //: situations. To become move-enabled a class needs to implement, at //: least, a move constructor. It should probably also implement a move //: assignment operator. //: 2 Users of a potentially move-enabled class may take advantage of moving //: objects by explicitly indicating that ownership of resources may be //: transferred. When using C++11 the compiler can automatically detect //: some situations where it is safe to move objects but this features is //: not available with C++03. // // The usage example below demonstrate both use cases using a simplified // version of 'std::Vector<T>'. The class template is simplified to // concentrate on the aspects relevant to 'bslmf::MovableRef<T>'. Most of the // operations are just normal implementations to create a container. The last // two operations described are using move operations. // // Assume we want to implement a class template similar to the standard library // 'vector' facility. First we declare the class template 'Vector<t_TYPE>'. // The definition of the this class template is rather straight forward, and // for simplicity a few trivial operations are implemented directly in the // class definition: //.. // template <class t_TYPE> // class Vector // { // t_TYPE *d_begin; // t_TYPE *d_end; // t_TYPE *d_endBuffer; // // static void swap(t_TYPE*& a, t_TYPE*& b); // // Swap the specified pointers 'a' and 'b'. // // public: // Vector(); // // Create an empty Vector. // // Vector(bslmf::MovableRef<Vector> other); // IMPLICIT // // Create a Vector by transferring the content of the specified // // 'other'. // // Vector(const Vector& other); // // Create a Vector by copying the content of the specified 'other'. // // Vector& operator= (Vector other); // // Assign a Vector by copying the content of the specified 'other' // // and return a reference to this object. Note that 'other' is // // passed by value to have the copy or move already be done, or // // even elided. Within the body of the assignment operator the // // content of 'this' and 'other' are simply swapped. // // ~Vector(); // // Destroy the Vector's elements and release any allocated memory. // // t_TYPE& operator[](int index) { return this->d_begin[index]; } // // Return a reference to the object at the specified 'index'. // // const t_TYPE& operator[](int index) const // { return this->d_begin[index]; } // // Return a reference to the object at the specified 'index'. // // t_TYPE *begin() { return this->d_begin; } // // Return a pointer to the first element. // // const t_TYPE *begin() const { return this->d_begin; } // // Return a pointer to the first element. // // int capacity() const { return int(this->d_endBuffer - this->d_begin); } // // Return the capacity of the Vector. // // bool empty() const { return this->d_begin == this->d_end; } // // Return 'true' if the Vector is empty and 'false' otherwise. // // t_TYPE *end() { return this->d_end; } // // Return a pointer to the end of the range. // // const t_TYPE *end() const { return this->d_end; } // // Return a pointer to the end of the range. // // void push_back(const t_TYPE& value); // // Append a copy of the specified 'value' to the Vector. // // void push_back(bslmf::MovableRef<t_TYPE> value); // // Append an object moving the specified 'value' to the new // // location. // // void reserve(int newCapacity); // // Reserve enough capacity to fit at least as many elements as // // specified by 'newCapacity'. // // int size() const { return int(this->d_end - this->d_begin); } // // Return the size of the object. // // void swap(Vector& other); // // Swap the content of the Vector with the specified 'other'. // }; //.. // The class stores pointers to the begin and the end of the elements as well // as a pointer to the end of the allocated buffer. If there are no elements, // null pointers are stored. There a number of accessors similar to the // accessors used by 'std::Vector<t_TYPE>'. // // The default constructor creates an empty 'Vector<t_TYPE>' by simply // initializing all member pointers to be null pointers: //.. // template <class t_TYPE> // Vector<t_TYPE>::Vector() // : d_begin() // , d_end() // , d_endBuffer() // { // } //.. // To leverage already implemented functionality some of the member functions // operate on a temporary 'Vector<t_TYPE>' and move the result into place using // the 'swap()' member function that simply does a memberwise 'swap()' (the // function swapping pointers is implemented here to avoid any dependency on // functions defined in another level): //.. // template <class t_TYPE> // void Vector<t_TYPE>::swap(t_TYPE*& a, t_TYPE*& b) // { // t_TYPE *tmp = a; // a = b; // b = tmp; // } // template <class t_TYPE> // void Vector<t_TYPE>::swap(Vector& other) // { // this->swap(this->d_begin, other.d_begin); // this->swap(this->d_end, other.d_end); // this->swap(this->d_endBuffer, other.d_endBuffer); // } //.. // The member function 'reserve()' arranges for the 'Vector<t_TYPE>' to have // enough capacity for the number of elements specified as argument. The // function first creates an empty 'Vector<t_TYPE>' called 'tmp' and sets 'tmp' // up to have enough capacity by allocating sufficient memory and assigning the // different members to point to the allocated buffer. The function then // iterates over the elements of 'this' and for each element it constructs a // new element in 'tmp'. //.. // template <class t_TYPE> // void Vector<t_TYPE>::reserve(int newCapacity) // { // if (this->capacity() < newCapacity) { // Vector tmp; // int size = int(sizeof(t_TYPE) * newCapacity); // tmp.d_begin = static_cast<t_TYPE*>(operator new(size)); // tmp.d_end = tmp.d_begin; // tmp.d_endBuffer = tmp.d_begin + newCapacity; // // for (t_TYPE* it = this->d_begin; it != this->d_end; ++it) { // new (tmp.d_end) t_TYPE(*it); // ++tmp.d_end; // } // this->swap(tmp); // } // } //.. // Any allocated data and constructed elements need to be release in the // destructor. The destructor does so by calling the destructor of the // elements in the buffer from back to front. Once the elements are destroyed // the buffer is released: //.. // template <class t_TYPE> // Vector<t_TYPE>::~Vector() // { // if (this->d_begin) { // while (this->d_begin != this->d_end) { // --this->d_end; // this->d_end->~t_TYPE(); // } // operator delete(this->d_begin); // } // } //.. // Using 'reserve()' and constructing the elements it is straight forward to // implement the copy constructor. First the member pointers are initialed to // null. If 'other' is empty there is nothing further to do as it is desirable // to not allocate a buffer for an empty 'Vector'. If there are elements to // copy the buffer is set up by calling 'reserve()' to create sufficient // capacity. Once that is done elements are copied by iterating over the // elements of 'other' and constructing elements using placement new in the // appropriate location. //.. // template <class t_TYPE> // Vector<t_TYPE>::Vector(const Vector& other) // : d_begin() // , d_end() // , d_endBuffer() // { // if (!other.empty()) { // this->reserve(4 < other.size()? other.size(): 4); // // ASSERT(other.size() <= this->capacity()); // for (t_TYPE* it = other.d_begin; it != other.d_end; ++it) { // new (this->d_end) t_TYPE(*it); // ++this->d_end; // } // } // } //.. // A simple copy assignment operator can be implemented in terms of copy/move // constructors, 'swap()', and destructor (in a real implementation the copy // assignment would probably try to use already allocated objects). In this // implementation that argument is taken by value, i.e., the argument is // already constructed using copy or move construction (which may have been // elided), the content of 'this' is swapped with the content of 'other' // leaving this in the desired state, and the destructor will release the // former representation of 'this' when 'other' is destroyed': //.. // template <class t_TYPE> // Vector<t_TYPE>& Vector<t_TYPE>::operator= (Vector other) // { // this->swap(other); // return *this; // } //.. // To complete the normal C++03 operations of 'Vector<t_TYPE>' the only // remaining member function is 'push_back()'. This function calls 'reserve()' // to obtain more capacity if the current capacity is filled and then // constructs the new element at the location pointed to by 'd_end': //.. // template <class t_TYPE> // void Vector<t_TYPE>::push_back(const t_TYPE& value) // { // if (this->d_end == this->d_endBuffer) { // this->reserve(this->size()? 2 * this->size() : 4); // } // assert(this->d_end != this->d_endBuffer); // new(this->d_end) t_TYPE(value); // ++this->d_end; // } //.. // The first operation actually demonstrating the use of 'MovableRef<t_TYPE>' // is the move constructor: //.. // template <class t_TYPE> // Vector<t_TYPE>::Vector(bslmf::MovableRef<Vector> other) // : d_begin(bslmf::MovableRefUtil::access(other).d_begin) // , d_end(bslmf::MovableRefUtil::access(other).d_end) // , d_endBuffer(bslmf::MovableRefUtil::access(other).d_endBuffer) // { // Vector& reference(other); // reference.d_begin = 0; // reference.d_end = 0; // reference.d_endBuffer = 0; // } //.. // This constructor gets an 'MovableRef<Vector<t_TYPE> >' passed as argument // that indicates that the referenced objects can be modified as long as it is // left in a state meeting the class invariants. The implementation of this // constructor first copies the 'd_begin', 'd_end', and 'd_capacity' members of // 'other'. Since 'other' is either an object of type // 'MovableRef<Vector<t_TYPE> >' (when compiling using a C++03 compiler) or an // r-value reference 'Vector<t_TYPE>&&' the members are accessed using // 'MovableRefUtil::access(other)' to get a reference to a 'Vector<t_TYPE>'. // Within the body of the constructor an l-value reference is obtained either // via the conversion operator of 'MovableRef<T>' or directly as 'other' is // just an l-value when compiling with a C++11 compiler. This reference is // used to set the pointer members of the object referenced by 'other' to '0' // completing the move of the content to the object under construction. // // Finally, a move version of 'push_back()' is provided: it takes an // 'MovableRef<t_TYPE>' as argument. The type of this argument indicates that // the state can be transferred and after arranging enough capacity in the // 'Vector<t_TYPE>' object a new element is move constructed at the position // 'd_end': //.. // template <class t_TYPE> // void Vector<t_TYPE>::push_back(bslmf::MovableRef<t_TYPE> value) // { // if (this->d_end == this->d_endBuffer) { // this->reserve(this->size()? int(1.5 * this->size()): 4); // } // assert(this->d_end != this->d_endBuffer); // new(this->d_end) t_TYPE(bslmf::MovableRefUtil::move(value)); // ++this->d_end; // } //.. // Note that this implementation of 'push_back()' uses // 'bslmf::MovableRefUtil::move(value)' to move the argument. For a C++03 // implementation the argument would be moved even when using 'value' directly // because the type of 'value' stays 'bslmf::MovableRef<t_TYPE>'. However, for // a C++11 implementation the argument 'value' is an l-value and using it // directly would result in a copy. // // To demonstrate the newly created 'Vector<t_TYPE>' class in action, first a // 'Vector<int>' is created and filled with a few elements: //.. // Vector<int> vector0; // for (int i = 0; i != 5; ++i) { // vector0.push_back(i); // } // for (int i = 0; i != 5; ++i) { // assert(vector0[i] == i); // } //.. // To verify that copying of 'Vector<t_TYPE>' objects works, a copy is created: //.. // Vector<int> vector1(vector0); // assert(vector1.size() == 5); // assert(vector1.size() == vector0.size()); // for (int i = 0; i != vector1.size(); ++i) { // assert(vector1[i] == i); // assert(vector1[i] == vector0[i]); // } //.. // When using moving this 'vector0' to a new location the representation of the // new object should use the original 'begin()': //.. // const int *first = vector0.begin(); // Vector<int> vector2(bslmf::MovableRefUtil::move(vector0)); // assert(first == vector2.begin()); //.. // When create a 'Vector<Vector<int> >' and using 'push_back()' on this object // with 'vector2' a copy should be inserted: //.. // Vector<Vector<int> > vVector; // vVector.push_back(vector2); // copy // assert(vector2.size() == 5); // assert(vVector.size() == 1); // assert(vVector[0].size() == vector2.size()); // assert(vVector[0].begin() != first); // for (int i = 0; i != 5; ++i) { // assert(vVector[0][i] == i); // assert(vector2[i] == i); // } //.. // When adding another element by moving 'vector2' the 'begin()' of the newly // inserted element will be the same as 'first', i.e., the representation is // transferred: //.. // vVector.push_back(bslmf::MovableRefUtil::move(vector2)); // move // assert(vVector.size() == 2); // assert(vVector[1].begin() == first); // assert(vVector[1].size() == 5); //.. // Compiling this code with both C++03 and C++11 compilers shows that there is // no need for conditional compilation in when using 'MovableRef<t_TYPE>' while // move semantics is enabled in both modes. // ---------------------------------------------------------------------------- #include <bslscm_version.h> #include <bslmf_addlvaluereference.h> #include <bslmf_addrvaluereference.h> #include <bslmf_decay.h> #include <bslmf_enableif.h> #include <bslmf_iscopyconstructible.h> #include <bslmf_islvaluereference.h> #include <bslmf_isnothrowmoveconstructible.h> #include <bslmf_isreference.h> #include <bslmf_isrvaluereference.h> #include <bslmf_removereference.h> #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_platform.h> #include <bsls_util.h> #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ defined(BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES) #define BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES // This macro indicates whether the component uses C++11 r-value references to // implement 'bslmf::MovableRef<t_TYPE>'. It will evaluate to 'false' for // C++03 implementations and to 'true' for proper C++11 implementations. For // partial C++11 implementations it may evaluate to 'false' because both // r-value reference and alias templates need to be supported. #endif #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) # define BSLMF_MOVABLEREF_DEDUCE(...) \ ::BloombergLP::bslmf::MovableRef_Deduced<__VA_ARGS__> // This macro expands to a movable reference to '__VA_ARGS__' for which the // arguments are deducible in all language versions. Note that the // argument list of this macro is variadic in order to support deducing // template arguments, e.g., this macro supports uses like // 'BSLMF_MOVABLEREF_DEDUCE(bsl::pair<T1, T2>)' for which the types 'T1' // and 'T2' are deducible, even though the macro argument contains a comma. #else # define BSLMF_MOVABLEREF_DEDUCE(...) \ ::BloombergLP::bslmf::MovableRef<__VA_ARGS__> #endif namespace BloombergLP { namespace bslmf { struct MovableRefUtil; // forward declaration template <class t_TYPE> struct MovableRefUtil_AddLvalueReference; // forward declaration template <class t_TYPE> struct MovableRefUtil_AddMovableReference; // forward declaration template <class t_TYPE> struct MovableRefUtil_Decay; // forward declaration template <class t_TYPE> struct MovableRefUtil_PropertyTraits; // forward declaration template <class t_TYPE> struct MovableRefUtil_RemoveReference; // forward declaration #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRef_Helper; // forward declaration #endif // =============== // type MovableRef // =============== #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> using MovableRef = typename MovableRef_Helper<t_TYPE>::type; // The alias template 'MovableRef<t_TYPE>' yields an r-value reference of // type 't_TYPE&&'. #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class t_TYPE> class MovableRef { // The class template 'MovableRef<t_TYPE>' provides a reference to a // movable object of type 't_TYPE'. Put differently, a function receiving // an object this class template can transfer (move) the representation to // a different object and leave the referenced object in an unspecified, // although valid (i.e., it obeys all class invariants), state. With C++11 // an r-value reference ('t_TYPE&&') is used to represent the same // semantics. // DATA t_TYPE *d_pointer; // PRIVATE CREATORS explicit MovableRef(t_TYPE *pointer); // Create an 'MovableRef<t_TYPE>' object referencing the object pointed // to by the specified 'pointer'. The behavior is undefined if // 'pointer' does not point to an object. This constructor is private // because a C++11 r-value reference cannot be created like this. For // information on how to create objects of type 'MovableRef<t_TYPE>' // see 'MovableRefUtil::move()'. // FRIENDS friend struct MovableRefUtil; public: // ACCESSORS operator t_TYPE&() const; // Return a reference to the referenced object. In contexts where a // reference to an object of type 't_TYPE' is needed, a // 'MovableRef<t_TYPE>' behaves like such a reference. For information // on how to access the reference in contexts where no conversion can // be used see 'MovableRefUtil::access()'. }; #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ===================== // struct MovableRefUtil // ===================== struct MovableRefUtil { // This 'struct' provides a collection of utility functions operating on // objects of type 'MovableRef<t_TYPE>'. The primary use of these // utilities to create a consistent notation for using the C++03 // 'MovableRef<t_TYPE>' objects and the C++11 't_TYPE&&' r-value // references. public: // TYPES template <class t_TYPE> struct IsLvalueReference : MovableRefUtil_PropertyTraits<t_TYPE>::IsLvalueReference { // This 'struct' template provides a Boolean metafunction that inherits // from 'bsl::true_type' if the specified 't_TYPE' is an lvalue // reference, and inherits from 'bsl::false_type' otherwise. }; template <class t_TYPE> struct IsMovableReference : MovableRefUtil_PropertyTraits<t_TYPE>::IsMovableReference { // This 'struct' template provides a Boolean metafunction that inherits // from 'bsl::true_type' if the specified 't_TYPE' is a specialization // of 'MovableRef', and inherits from 'bsl::false_type' otherwise. }; template <class t_TYPE> struct IsReference : MovableRefUtil_PropertyTraits<t_TYPE>::IsReference { // This 'struct' template provides a Boolean metafunction that inherits // from 'bsl::true_type' if the specified 't_TYPE' is either an lvalue // reference or a specialization of 'MovableRef', and inherits from // 'bsl::false_type' otherwise. }; template <class t_TYPE> struct RemoveReference : MovableRefUtil_RemoveReference<t_TYPE> { // This 'struct' template provides a metafunction that, if the // specified 't_TYPE' is a reference type, defines a nested 'type' // typedef of the type to which 't_TYPE' refers, and defines a nested // 'type' typedef of 't_TYPE' otherwise. }; template <class t_TYPE> struct AddLvalueReference : MovableRefUtil_AddLvalueReference<t_TYPE> { // This 'struct' template provides a metafunction that defines a nested // 'type' typedef that is an lvalue reference to 't_TYPE'. If 't_TYPE' // is already an 'lvalue' reference, then 'type' is 't_TYPE'. // Otherwise, if 't_TYPE' is 'MovableRef<T2>', then 'type' is 'T2&'. // This transformation reflects the semantics of _reference collapsing_ // in section [dec.ref] of the standard. }; template <class t_TYPE> struct AddMovableReference : MovableRefUtil_AddMovableReference<t_TYPE> { // This 'struct' template provides a metafunction that defines a nested // 'type' typedef that, if 't_TYPE' is not a reference type, is // 'MovableRef<t_TYPE>'. Otherwise, if 't_TYPE' is a specialization of // 'MovableRef', 'type' is the same as 't_TYPE'. Otherwise, 'type' is // 't_TYPE&'. This transformation reflects the semantics of // _reference collapsing_ in section [dec.ref] of the standard. }; template <class t_TYPE> struct Decay : MovableRefUtil_Decay<t_TYPE> { // This 'struct' template provides a metafunction that defines a nested // 'type' typedef that applies lvalue-to-rvalue, array-to-pointer, and // function-to-pointer conversions that occur when an lvalue of type // 't_TYPE' is used as an rvalue, and also removes 'const', 'volatile', // and reference qualifiers from class types in order to model by-value // argument passing. For the purpose of this type trait, // 'MovableRef<T>' is considered a (movable) reference-qualified 'T'. // // Formally, let 'U' be // 'MovableRefUtil::RemoveReference<t_TYPE>::type'. If // 'bsl::is_array<U>::value' is true, the member typedef 'type' is // 'bsl::remove_extent<U>::type *'. If 'bsl::is_function<U>::value' is // true, the member typedef 'type' is 'bsl::add_pointer<U>::type'. // Otherwise, the member typedef 'type' is 'bsl::remove_cv<U>::type'. }; // CLASS METHODS #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> static typename bsl::remove_reference<t_TYPE>::type& access( t_TYPE&& ref) BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> static t_TYPE& access(t_TYPE& ref) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> static t_TYPE& access(MovableRef<t_TYPE> ref) BSLS_KEYWORD_NOEXCEPT; #endif // Return an lvalue reference to the object referenced by the specified // 'ref' object. This function is used to provide a uniform interface to // members of an object reference by 'ref', regardless of whether 'ref' is // an 'MovableRef' or lvalue reference and whether the compiler supports // C++11 rvalue references. This function is unnecessary (but allowed) // when simply converting 'ref' to 't_TYPE&'. // // Please see the component-level documentation for more information on // this function. #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> static BSLS_KEYWORD_CONSTEXPR MovableRef<typename bsl::remove_reference<t_TYPE>::type> move(t_TYPE&& reference) BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> static MovableRef<t_TYPE> move(t_TYPE& reference) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> static MovableRef<typename bsl::remove_reference<t_TYPE>::type> move( MovableRef<t_TYPE> reference) BSLS_KEYWORD_NOEXCEPT; #endif // Return a movable reference to the object referred to by the specified // 'reference'. Note that the C++03 implementation of this function // behaves like a factory for 'MovableRef<t_TYPE>' objects. The C++11 // implementation of this function behaves exactly like 'std::move(value)' // applied to lvalues. template <class t_TYPE> static typename bsl::enable_if< !bsl::is_nothrow_move_constructible<t_TYPE>::value && bsl::is_copy_constructible<t_TYPE>::value, const t_TYPE&>::type move_if_noexcept(t_TYPE& lvalue) BSLS_KEYWORD_NOEXCEPT // Return a const-qualified reference to the specified 'lvalue'. This // function is selected by overload resolution if the move constructor // for 't_TYPE' might throw an exception. Constructing a 't_TYPE' // object from the result will result in the copy constructor being // invoked rather than the (unsafe) move constructor. { // The implementation is placed here in the class definition to work // around a Microsoft C++ compiler (version 16) bug where the // definition cannot be matched to the declaration when an 'enable_if' // is used. return lvalue; } template <class t_TYPE> static typename bsl::enable_if< !bsl::is_copy_constructible<t_TYPE>::value || bsl::is_nothrow_move_constructible<t_TYPE>::value, MovableRef<t_TYPE> >::type move_if_noexcept(t_TYPE& lvalue) BSLS_KEYWORD_NOEXCEPT // Return a movable reference to the specified 'lvalue'. This function // is selected by overload resolution if the move constructor for // 't_TYPE' is nothrow-move-constructible. Constructing a 't_TYPE' // object from the result will result in the (safe) move constructor // being invoked. Note that that the // 'bsl::is_nothrow_move_constructible' trait can be customized in // C++03 mode to indicate that a type is nothrow-move-constructible. { // The implementation is placed here in the class definition to work // around a Microsoft C++ compiler (version 16) bug where the // definition cannot be matched to the declaration when an 'enable_if' // is used. #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES return static_cast<typename bsl::remove_reference<t_TYPE>::type&&>( lvalue); #else return MovableRef<t_TYPE>(bsls::Util::addressOf(lvalue)); #endif } }; #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES // ======================== // struct MovableRef_Helper // ======================== template <class t_TYPE> struct MovableRef_Helper { // The class template 'MovableRef_Helper' just defines a nested type // 'type' that is used by an alias template. Using this indirection the // template argument of the alias template is prevented from being deduced. public: // TYPES using type = t_TYPE&&; // The type 'type' defined to be an r-value reference to the argument // type of 'MovableRef_Helper. }; // ======================= // type MovableRef_Deduced // ======================= template <class t_TYPE, typename bsl::enable_if<!bsl::is_lvalue_reference<t_TYPE>::value, int>::type = 0> using MovableRef_Deduced = t_TYPE&&; // This component-private alias template names the type 't_TYPE&&' if and // only if the specified 't_TYPE' is not an lvalue reference. #endif // defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------- // class MovableRef // ---------------- #ifndef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES // CREATORS template <class t_TYPE> inline MovableRef<t_TYPE>::MovableRef(t_TYPE *pointer) : d_pointer(pointer) { BSLS_ASSERT(0 != pointer); } // ACCESSORS template <class t_TYPE> inline MovableRef<t_TYPE>::operator t_TYPE&() const { return *d_pointer; } #endif // defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // --------------------- // struct MovableRefUtil // --------------------- #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES // CLASS METHODS template <class t_TYPE> inline typename bsl::remove_reference<t_TYPE>::type& MovableRefUtil::access( t_TYPE&& ref) BSLS_KEYWORD_NOEXCEPT { return ref; } #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class t_TYPE> inline t_TYPE& MovableRefUtil::access(t_TYPE& ref) BSLS_KEYWORD_NOEXCEPT { return ref; } template <class t_TYPE> inline t_TYPE& MovableRefUtil::access(MovableRef<t_TYPE> ref) BSLS_KEYWORD_NOEXCEPT { return ref; } #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> inline BSLS_KEYWORD_CONSTEXPR MovableRef<typename bsl::remove_reference<t_TYPE>::type> MovableRefUtil::move(t_TYPE&& rvalue) BSLS_KEYWORD_NOEXCEPT { return static_cast<typename bsl::remove_reference<t_TYPE>::type&&>(rvalue); } #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class t_TYPE> inline MovableRef<t_TYPE> MovableRefUtil::move(t_TYPE& lvalue) BSLS_KEYWORD_NOEXCEPT { return MovableRef<t_TYPE>(bsls::Util::addressOf(lvalue)); } template <class t_TYPE> inline MovableRef<typename bsl::remove_reference<t_TYPE>::type> MovableRefUtil::move( MovableRef<t_TYPE> rvalue) BSLS_KEYWORD_NOEXCEPT { return rvalue; } #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ------------------------------------ // struct MovableRefUtil_PropertyTraits // ------------------------------------ #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRefUtil_PropertyTraits { // Component-private class: do not use. Define Boolean-valued // movable-reference traits for the specified 't_TYPE'. // TYPES typedef bsl::is_lvalue_reference<t_TYPE> IsLvalueReference; typedef bsl::is_rvalue_reference<t_TYPE> IsMovableReference; typedef bsl::is_reference<t_TYPE> IsReference; }; #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class t_TYPE> struct MovableRefUtil_PropertyTraits { // Component-private class: do not use. Define Boolean-valued // movable-reference traits for rvalues of the specified 't_TYPE'. typedef bsl::false_type IsLvalueReference; typedef bsl::false_type IsMovableReference; typedef bsl::false_type IsReference; }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<t_TYPE&> { // Component-private class: do not use. Define Boolean-valued // movable-reference traits for lvalues of the specified 't_TYPE'. typedef bsl::true_type IsLvalueReference; typedef bsl::false_type IsMovableReference; typedef bsl::true_type IsReference; }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<MovableRef<t_TYPE> > { // Component-private class: do not use. Define Boolean-valued // movable-reference traits for movable references to the specified // 't_TYPE'. typedef bsl::false_type IsLvalueReference; typedef bsl::true_type IsMovableReference; typedef bsl::true_type IsReference; }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<MovableRef<t_TYPE>&> : MovableRefUtil_PropertyTraits<MovableRef<t_TYPE> > { }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<const MovableRef<t_TYPE> > : MovableRefUtil_PropertyTraits<MovableRef<t_TYPE> > { }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<const MovableRef<t_TYPE>&> : MovableRefUtil_PropertyTraits<MovableRef<t_TYPE> > { }; template <class t_TYPE> struct MovableRefUtil_PropertyTraits<volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_PropertyTraits<volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_PropertyTraits<const volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_PropertyTraits<const volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ------------------------------------- // struct MovableRefUtil_RemoveReference // ------------------------------------- #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRefUtil_RemoveReference : bsl::remove_reference<t_TYPE> { // This component-private 'struct' template provides a metafunction that, // if the specified 't_TYPE' is a reference type, defines a nested 'type' // typedef of the type to which 't_TYPE' refers, and defines a nested // 'type' typedef of 't_TYPE' otherwise. }; #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class t_TYPE> struct MovableRefUtil_RemoveReference { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<t_TYPE&> { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<bslmf::MovableRef<t_TYPE> > { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<bslmf::MovableRef<t_TYPE>&> { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<const bslmf::MovableRef<t_TYPE> > { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<const bslmf::MovableRef<t_TYPE>&> { // TYPES typedef t_TYPE type; }; template <class t_TYPE> struct MovableRefUtil_RemoveReference<volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_RemoveReference<volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_RemoveReference<const volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_RemoveReference<const volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ---------------------------------------- // struct MovableRefUtil_AddLvalueReference // ---------------------------------------- #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRefUtil_AddLvalueReference : bsl::add_lvalue_reference<t_TYPE> { // This component-private 'struct' template provides a metafunction that // defines a nested 'type' typedef that is an lvalue reference to 't_TYPE'. // If 't_TYPE' is already an 'lvalue' reference, then 'type' is 't_TYPE'. // Otherwise, if 't_TYPE' is 'MovableRef<T2>', then 'type' is 'T2&'. This // transformation reflects the semantics of _reference collapsing_ in // section [dec.ref] of the standard. }; #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <> struct MovableRefUtil_AddLvalueReference<void> { // TYPES typedef void type; }; template <> struct MovableRefUtil_AddLvalueReference<const void> { // TYPES typedef const void type; }; template <> struct MovableRefUtil_AddLvalueReference<volatile void> { // TYPES typedef volatile void type; }; template <> struct MovableRefUtil_AddLvalueReference<const volatile void> { // TYPES typedef const volatile void type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<t_TYPE&> { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<MovableRef<t_TYPE> > { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<MovableRef<t_TYPE>&> { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<const MovableRef<t_TYPE> > { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<const MovableRef<t_TYPE>&> { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<const volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddLvalueReference<const volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // ----------------------------------------- // struct MovableRefUtil_AddMovableReference // ----------------------------------------- #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRefUtil_AddMovableReference : bsl::add_rvalue_reference<t_TYPE> { // This component-private 'struct' template provides a metafunction that // defines a nested 'type' typedef that, if 't_TYPE' is not a reference // type, is 'MovableRef<t_TYPE>'. Otherwise, if 't_TYPE' is a // specialization of 'MovableRef', 'type' is the same as 't_TYPE'. // Otherwise, 'type' is 't_TYPE&'. This transformation reflects the // semantics of // _reference collapsing_ in section [dec.ref] of the standard. }; #else // if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <> struct MovableRefUtil_AddMovableReference<void> { // TYPES typedef void type; }; template <> struct MovableRefUtil_AddMovableReference<const void> { // TYPES typedef const void type; }; template <> struct MovableRefUtil_AddMovableReference<volatile void> { // TYPES typedef volatile void type; }; template <> struct MovableRefUtil_AddMovableReference<const volatile void> { // TYPES typedef const volatile void type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference { // TYPES typedef bslmf::MovableRef<t_TYPE> type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<t_TYPE&> { // TYPES typedef t_TYPE& type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<MovableRef<t_TYPE> > { // TYPES typedef bslmf::MovableRef<t_TYPE> type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<MovableRef<t_TYPE>&> { // TYPES typedef bslmf::MovableRef<t_TYPE> type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<const MovableRef<t_TYPE> > { // TYPES typedef bslmf::MovableRef<t_TYPE> type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<const MovableRef<t_TYPE>&> { // TYPES typedef bslmf::MovableRef<t_TYPE> type; }; template <class t_TYPE> struct MovableRefUtil_AddMovableReference<volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddMovableReference<volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddMovableReference<const volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_AddMovableReference<const volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) // --------------------------- // struct MovableRefUtil_Decay // --------------------------- #ifdef BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES template <class t_TYPE> struct MovableRefUtil_Decay : bsl::decay<t_TYPE> { // This component-private 'struct' template provides a metafunction that // defines a nested 'type' typedef that applies lvalue-to-rvalue, // array-to-pointer, and function-to-pointer conversions that occur when an // lvalue of type 't_TYPE' is used as an rvalue, and also removes 'const', // 'volatile', and reference qualifiers from class types in order to model // by-value argument passing. For the purpose of this type trait, // 'MovableRef<T>' is considered a (movable) reference-qualified 'T'. // // Formally, let 'U' be 'MovableRefUtil::RemoveReference<t_TYPE>::type'. // If 'bsl::is_array<U>::value' is true, the member typedef 'type' is // 'bsl::remove_extent<U>::type *'. If 'bsl::is_function<U>::value' is // true, the member typedef 'type' is 'bsl::add_pointer<U>::type'. // Otherwise, the member typedef 'type' is 'bsl::remove_cv<U>::type'. }; #elif !defined(BSLS_PLATFORM_CMP_IBM) || BSLS_PLATFORM_CMP_VERSION > 4097 ///Implementation Note ///- - - - - - - - - - // The following definition of 'MovableRefUtil_Decay' is for C++03 compilers, // *except* versions of IBM XL C++ prior to 16.0.2. template <class t_TYPE> struct MovableRefUtil_Decay : bsl::decay<typename MovableRefUtil_RemoveReference<t_TYPE>::type> { }; #else ///Implementation Note ///- - - - - - - - - - // The following implementation of 'MovableRefUtil_Decay' is exclusively for // the IBM XL C++ line of compilers prior to version 16.0.2. This line of // compilers has a defect in which the compiler retains default-argument // information in the type of functions that have default arguments. If the // program attempts to form a typedef to the type of a function with default // arguments, the IBM XL C++ compiler rejects the typedef because it attempts // to form it with default arguments. Since default arguments cannot be // specified anywhere except function declarations, compilation then fails. // // For example, the following code will be rejected: //.. // void f(int = 0); // // template <class t_TYPE> // void g(t_TYPE) // { // typedef t_TYPE type; // ERROR: Default arguments cannot be specified // // in a 'typedef'. // } // // void example() // { // g(f); // ERROR: From the 'g' template instantiation here. // } //.. // However, typedefs to *pointers* to such function types do not run afoul of // this defect. Fortunately, the specification of 'decay' requires // transforming function types and reference-to-function types to // pointer-to-function types. So, with some careful metaprogramming, the // following implementation avoids triggering this defect. template <class t_TYPE, bool t_IS_FUNCTION = bsl::is_function<t_TYPE>::value> struct MovableRefUtil_DecayImp; template <class t_TYPE> struct MovableRefUtil_DecayImp<t_TYPE, /* t_IS_FUNCTION */ false> : bsl::decay<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_DecayImp<t_TYPE, /* t_IS_FUNCTION */ true> { typedef t_TYPE *type; }; template <class t_TYPE> struct MovableRefUtil_Decay : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<t_TYPE&> : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<MovableRef<t_TYPE> > : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<MovableRef<t_TYPE>&> : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<const MovableRef<t_TYPE> > : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<const MovableRef<t_TYPE>&> : MovableRefUtil_DecayImp<t_TYPE> { }; template <class t_TYPE> struct MovableRefUtil_Decay<volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_Decay<volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_Decay<const volatile MovableRef<t_TYPE> >; // This partial 'struct' template specialization is not defined. template <class t_TYPE> struct MovableRefUtil_Decay<const volatile MovableRef<t_TYPE>&>; // This partial 'struct' template specialization is not defined. #endif // !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // 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 ----------------------------------