// bslmf_util.h -*-C++-*- #ifndef INCLUDED_BSLMF_UTIL #define INCLUDED_BSLMF_UTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide low-level functions on 'bslmf' types. // //@CLASSES: // bslmf::Util: utility class providing low-level functionality // //@DESCRIPTION: This component defines a utility 'struct', 'bslmf::Util', that // serves as a namespace for a suite of functions that supply low-level // functionality for implementing portable generic facilities such as might be // found in the C++ standard library. // ///'bslmf::Util::forward' ///---------------------- // The function 'forward' emulates the C++ standard utility function // 'std::forward' with the addition that on compilers that don't support // r-value references (i.e., C++03) a 'bslmf::MovableRef<t_T>' is forwarded as // a 'bslmf::MovableRef<t_T>'. This operation is typically used via // 'BSLS_COMPILERFEATURES_FORWARD' (along with // 'BSLS_COMPILERFEATURES_FORWARD_REF') when forwarding arguments in a generic // context. See {Usage}. // ///'bslmf::Util::forwardAsReference' ///--------------------------------- // The function 'forwardAsReference', like 'forward', emulates the C++ standard // utility function 'std::forward' with the difference that on compilers that // don't support r-value references (C++03) a 'bslmf::MovableRef<t_T>' is // forwarded as 'const t_T&' (instead of 'bslmf::MovableRef<t_T>'). This // operation is intended to be used when forwarding a 'MovableRef<t_T>' where // that 'MovableRef' is being supplied to a function that does not support // 'move' emulation, but will support true C++11 r-value references (e.g., // 'bdlf::BindUtil::bind'). // ///'bslmf::Util::moveIfSupported' ///------------------------------ // The function 'moveIfSupported' emulates the C++ standard utility function // 'std::move' with the addition that on compilers that don't support r-value // references (i.e., C++03) an l-value reference is returned instead. This // operation is intended to be used when moving an object to a function that // does not support 'move' emulation, but will support true C++11 r-value // references (e.g., 'bdlf::BindUtil::bind'). // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Using 'bslmf::Util::forward' ///--------------------------------------- // Clients should generally not use 'bslmf::Util::forward' directly, instead it // should be used via 'BSLS_COMPILERFEATURES_FORWARD' in conjunction with // 'BSLS_COMPILERFEATURES_FORWARD_REF'. Here we show a simple function using // 'BSLS_COMPILERFEATURES_FORWARD': //.. // template <class RESULT_TYPE> // struct FactoryUtil { // // template <class ARG_TYPE> // RESULT_TYPE create(BSLS_COMPILERFEATURES_FORWARD_REF(ARG_TYPE) arg) { // return RESULT_TYPE(BSLS_COMPILERFEATURES_FORWARD(ARG_TYPE, arg)); // } // }; //.. // Notice that 'bslmf::Util::forward' is only used in conjunction with // 'BSLS_COMPILERFEATURES_FORWARD_REF' because, in the example above, if the // 'create' function's parameter type was 'ARG_TYPE&& ' then it is a // C++11-only(!) forwarding reference, and we would simply use the standard // 'std::forward'. Alternatively, if the parameter type was // 'MovableRef<ARG_TYPE>' then 'arg' is *not* a forwarding-reference to be // forwarded (certainly not in C++03). // ///Example 2: Using 'bslmf::Util::forwardAsReference' ///-------------------------------------------------- // Suppose we had a template facility, 'MyBindUtil::bind' that does not support // 'bslmf::MovableRef', but will accept true r-value references (on supported // compilers). Here we use 'forwardAsReference' to forward a supplied // 'bslmf::MovableRef' as a true r-value reference (on supporting compilers), // and a const reference otherwise. Note that the definitions of 'MyFunction' // and 'MyBindUtil' are elided and meant to represent 'bsl::function' and // 'bdlf::BindUtil::bind' respectively: //.. // void doSomething(bslmf::MovableRef<Foo> value) // { // MyFunction f = MyBindUtil::bind( // bslmf::Util::forwardAsReference<Foo>(value)); // // //... // } //.. // Note that because 'MyBindUtil::bind' does not support 'MovableRef', without // 'forwardAsReference' the call to 'bind' might either fail to compile, or // worse, bind the 'MyFunction' instance to a reference to 'value' (rather a // new object moved-from 'value') on C++03 platforms. // ///Example 3: Using 'bslmf::Util::moveIfSupported' ///----------------------------------------------- // Suppose we had a template facility, 'MyBindUtil::bind' that does not support // 'bslmf::MovableRef', but will accept true r-value references (on supported // compilers). Here we use 'moveIfSupported' to move a supplied 'value' if // the compiler suppots r-value references, and copy it otherwise. Note that // the definitions of 'MyFunction' and 'MyBindUtil' are elided and meant to // represent 'bsl::function' and 'bdlf::BindUtil::bind' respectively: //.. // void doSomething2(Foo value) // { // MyFunction f = MyBindUtil::bind(bslmf::Util::moveIfSupported(value)); // // //... // } //.. // Note that because 'MyBindUtil::bind' does not support 'MovableRef', without // 'moveIfSupported' the call to 'bind' might either fail to compile, or // worse, bind the 'MyFunction' instance to a reference to 'value' (rather a // new object moved-from 'value') on C++03 platforms. #include <bslscm_version.h> #include <bslmf_addlvaluereference.h> #include <bslmf_addrvaluereference.h> #include <bslmf_movableref.h> #include <bslmf_removereference.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> namespace BloombergLP { namespace bslmf { // =========== // struct Util // =========== struct Util { // This struct provides several functions that are specified in the // <utility> header of the C++ Standard, in order to support the 'bsl' // library implementation without cycles into the native standard library, // and on platforms with only C++03 compilers available, where library // features may be emulated. // CLASS METHODS #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static t_TYPE&& forward( typename bsl::remove_reference<t_TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static t_TYPE&& forward( typename bsl::remove_reference<t_TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static const t_TYPE& forward( const t_TYPE& t) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static MovableRef<t_TYPE> forward( MovableRef<t_TYPE> t) BSLS_KEYWORD_NOEXCEPT; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // Correctly forward the specified 't' argument based on the current // compilation environment. #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static typename bsl::add_rvalue_reference<t_TYPE>::type declval() BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static typename bsl::add_lvalue_reference<t_TYPE>::type declval() BSLS_KEYWORD_NOEXCEPT; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // This function has no implementation. It exists to allow for the // appearance of a temporary object of the specified type that can be // used in unevaluated contexts. #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static t_TYPE&& forwardAsReference( typename bsl::remove_reference<t_TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static t_TYPE&& forwardAsReference( typename bsl::remove_reference<t_TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static const t_TYPE& forwardAsReference( const t_TYPE& t) BSLS_KEYWORD_NOEXCEPT; template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static const t_TYPE& forwardAsReference( MovableRef<t_TYPE> t) BSLS_KEYWORD_NOEXCEPT; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // Correctly forward the specified 't' argument as a reference type // based on the current compilation environment. Note that this // function differs from 'forward' in that when using a C++03 compiler, // 'MovableRef<t_T>' is forwarded as 'const t_T&' (rather than // 'MovableRef<t_T>'), which is important when forwarding to a facility // (e.g., 'bdlf::BindUtil::bind') which does not support // 'bslmf::MovableRef'. #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static typename bsl::remove_reference<t_TYPE>::type&& moveIfSupported(t_TYPE&& t) BSLS_KEYWORD_NOEXCEPT; #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR static typename bsl::remove_reference<t_TYPE>::type& moveIfSupported(t_TYPE& t) BSLS_KEYWORD_NOEXCEPT; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // Return an r-value reference to the specified 't' argument. If // r-value references are not supported, return an l-value reference. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // CLASS METHODS #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline t_TYPE&& Util::forward( typename bsl::remove_reference<t_TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<t_TYPE&&>(t); } template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline t_TYPE&& Util::forward( typename bsl::remove_reference<t_TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<t_TYPE&&>(t); } #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline const t_TYPE& Util::forward(const t_TYPE& t) BSLS_KEYWORD_NOEXCEPT { return t; } template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline bslmf::MovableRef<t_TYPE> Util::forward( bslmf::MovableRef<t_TYPE> t) BSLS_KEYWORD_NOEXCEPT { return t; } #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline t_TYPE&& Util::forwardAsReference( typename bsl::remove_reference<t_TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<t_TYPE&&>(t); } template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline t_TYPE&& Util::forwardAsReference( typename bsl::remove_reference<t_TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<t_TYPE&&>(t); } #else template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline const t_TYPE& Util::forwardAsReference(const t_TYPE& t) BSLS_KEYWORD_NOEXCEPT { return t; } template <class t_TYPE> BSLS_KEYWORD_CONSTEXPR inline const t_TYPE& Util::forwardAsReference( bslmf::MovableRef<t_TYPE> t) BSLS_KEYWORD_NOEXCEPT { return bslmf::MovableRefUtil::access(t); } #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_T> BSLS_KEYWORD_CONSTEXPR inline typename bsl::remove_reference<t_T>::type&& Util::moveIfSupported( t_T&& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<typename bsl::remove_reference<t_T>::type&&>(t); } #else template <class t_T> BSLS_KEYWORD_CONSTEXPR inline typename bsl::remove_reference<t_T>::type& Util::moveIfSupported( t_T& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<typename bsl::remove_reference<t_T>::type&>(t); } #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2016 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 ----------------------------------