// bslmf_isnothrowmoveconstructible.h -*-C++-*- #ifndef INCLUDED_BSLMF_ISNOTHROWMOVECONSTRUCTIBLE #define INCLUDED_BSLMF_ISNOTHROWMOVECONSTRUCTIBLE #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide metafunction to identify no-throw move-constructible types. // //@CLASSES: // bsl::is_nothrow_move_constructible: type-traits metafunction // bsl::is_nothrow_move_constructible_v: the metafunction's result value // //@SEE_ALSO: bslmf_integralconstant, bslmf_nestedtraitdeclaration, // bslmf_movableref // //@DESCRIPTION: This component defines a metafunction, // 'bsl::is_nothrow_move_constructible', and a variable template // 'bsl::is_nothrow_move_constructible_v' that represents the result value of // the 'bsl::is_nothrow_move_constructible' metafunction, which may be used to // query whether a type has a constructor that can be called with a single // rvalue that is known to not throw exceptions. Note that a C++11 compiler // will automatically infer this trait for class types with a move constructor // that is marked as 'noexcept'. // // 'bsl::is_nothrow_move_constructible' meets the requirements of the // 'is_nothrow_move_constructible' template defined in the C++11 standard. // // Note that the template variable 'is_nothrow_move_constructible_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_nothrow_move_constructible_v' is defined as an 'inline constexpr // bool' variable. Otherwise, if the compiler supports the variable templates // C++14 compiler feature, 'bsl::is_nothrow_move_constructible_v' is defined as // a non-inline 'constexpr bool' variable. See // 'BSLS_COMPILERFEATURES_SUPPORT_INLINE_VARIABLES' and // 'BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES' macros in the // bsls_compilerfeatures component for details. #include <bslscm_version.h> #include <bslmf_assert.h> #include <bslmf_detectnestedtrait.h> #include <bslmf_integralconstant.h> #include <bslmf_isarray.h> #include <bslmf_isconst.h> #include <bslmf_istriviallycopyable.h> #include <bslmf_isvolatile.h> #include <bslmf_voidtype.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_platform.h> #include <stddef.h> #ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER # include <type_traits> #endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bsls_nativestd.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace bsl { template <class t_TYPE> struct is_nothrow_move_constructible; } // close namespace bsl ///Implementation Notes ///-------------------- // In C++20 certain array types which decay to their element type, such as // 'const void*' and 'bool', report as copy constructible through // 'std::is_nothrow_move_constructible'. In fact, initialization that attempts // such move constructions does not result in a copy of the orginal array but // instead initializes only the first element of the new array -- and that is // set to the address of the original array, not the original's first element. // // This behavior has been observed in 'gcc-11' targeting C++20 and should occur // with any compiler correctly supporting C++20 aggregate initialization with // parenthesis (identified by the feature test macro // '__cpp_aggregate_paren_init'). // // An LWG issue (https://wg21.link/lwg####) has been filed to correct this // behavior and continue to return 'false' for all array types. // // The implementation below preemptively implements the expected resolution of // that issue on all platforms. #define STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(t_TYPE) \ (bsl::is_array<t_TYPE>::value \ ? false \ : ::std::is_nothrow_move_constructible<t_TYPE>::value) namespace BloombergLP { namespace bslmf { // ===================================== // struct IsNothrowMoveConstructible_Imp // ===================================== #if defined(BSLS_PLATFORM_CMP_SUN) && \ (BSLS_PLATFORM_CMP_VERSION == 0x5150) && \ (BSLS_COMPILERFEATURES_CPLUSPLUS == 199711L) // Solaris 12.6 compiler in C++03 mode treats as ambiguous partial // specializations with `t_TYPE` and with cv-qualified `t_TYPE`. #define BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE) \ typename bsl::enable_if<!bsl::is_const<t_TYPE>::value && \ !bsl::is_volatile<t_TYPE>::value, \ BSLMF_VOIDTYPE(int t_TYPE::*)>::type #else #define BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE) \ BSLMF_VOIDTYPE(int t_TYPE::*) #endif #if defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER) template <class t_TYPE, class = void> struct IsNothrowMoveConstructible_Impl : bsl::integral_constant<bool, STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(t_TYPE)> { // This 'struct' template implements a metafunction to determine whether // the (non-cv-qualified) (template parameter) 't_TYPE' has a no-throw move // constructor. Note that the partial specializations below will provide // the determination for class types. }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::integral_constant< bool, STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(t_TYPE) || bsl::is_trivially_copyable<t_TYPE>::value || DetectNestedTrait<t_TYPE, bsl::is_nothrow_move_constructible>::value> { // This 'struct' template implements a metafunction to determine whether // the (non-cv-qualified) (template parameter) 't_TYPE' has a no-throw move // constructor. To maintain consistency between the C++03 and C++11 // implementations of this trait, types that use the BDE trait association // techniques are also detected as no-throw move constructible, even if the // 'noexcept' operator would draw a different conclusion. enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< const t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::integral_constant< bool, STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(const t_TYPE) || bsl::is_trivially_copyable<t_TYPE>::value> { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< volatile t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::integral_constant< bool, STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(volatile t_TYPE)> { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< const volatile t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::integral_constant< bool, STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE(const volatile t_TYPE)> { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; // Partial specializations to avoid detecting cv-qualified class types with // nested trait declarations as having no-throw constructors that take // cv-qualified rvalues unless those constructors are actually detected as // non-throwing. Note that volatile-qualified scalar types will detect as // no-throw move constructible through the primary template. In addition, // we flag types that specialize 'bsl::is_trivially_copyable' as no-throw // move constructible to maintain consistency between the C++03 and C++11 // implementations of this trait. #undef STD_IS_NOTHROW_MOVE_CONSTRUCTIBLE_VALUE #else template <class t_TYPE, class = void> struct IsNothrowMoveConstructible_Impl : bsl::is_trivially_copyable<t_TYPE>::type { // This 'struct' template implements a metafunction to determine whether // the (non-cv-qualified) (template parameter) 't_TYPE' has a no-throw move // constructor. For C++03, the set of types known to be no-throw move // constructible are all trivial types. Note that the partial // specializations below will provide the determination for class types, // and this primary template is equivalent to querying whether 't_TYPE' is // a scalar type. }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::integral_constant< bool, bsl::is_trivially_copyable<t_TYPE>::value || DetectNestedTrait<t_TYPE, bsl::is_nothrow_move_constructible>::value> { // This 'struct' template implements a metafunction to determine whether // the (non-cv-qualified) (template parameter) 't_TYPE' has a no-throw move // constructor. To maintain consistency between the C++03 and C++11 // implementations of this trait, types that use the BDE trait association // techniques are also detected as no-throw move constructible, even if the // 'noexcept' operator would draw a different conclusion. enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< const t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::is_trivially_copyable<t_TYPE>::type { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< volatile t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::false_type { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl< const volatile t_TYPE, BSLMF_ISNOTHROWMOVECONSTRUCTIBLE_VOIDTYPE(t_TYPE)> : bsl::false_type { enum { k_CHECK_COMPLETE = sizeof(t_TYPE) }; // Diagnose incomplete types }; // Partial specializations to avoid detecting cv-qualified class types with // nested trait declarations as having no-throw constructors that take // cv-qualified rvalues unless those constructors are actually detected. // Note that volatile-qualified scalar types will detect as no-throw move // constructible through the primary template. As a practical matter, we // assume that types flagged as trivially copyable have a no-throw copy // constructor, and so are no-throw move constructible too. #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<t_TYPE&&> : bsl::true_type { }; #endif template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<t_TYPE&> : bsl::true_type { }; // Partial specializations to indicate that reference binding from an // identical reference can never throw. template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<t_TYPE[]> : bsl::false_type { }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<const t_TYPE[]> : bsl::false_type { }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<volatile t_TYPE[]> : bsl::false_type { }; template <class t_TYPE> struct IsNothrowMoveConstructible_Impl<const volatile t_TYPE[]> : bsl::false_type { }; template <class t_TYPE, size_t t_LEN> struct IsNothrowMoveConstructible_Impl<t_TYPE[t_LEN]> : bsl::false_type { }; template <class t_TYPE, size_t t_LEN> struct IsNothrowMoveConstructible_Impl<const t_TYPE[t_LEN]> : bsl::false_type { }; template <class t_TYPE, size_t t_LEN> struct IsNothrowMoveConstructible_Impl<volatile t_TYPE[t_LEN]> : bsl::false_type { }; template <class t_TYPE, size_t t_LEN> struct IsNothrowMoveConstructible_Impl<const volatile t_TYPE[t_LEN]> : bsl::false_type { }; // These partial specializations ensure that array types are not detected // as move constructible. Note that while array data members of classes // will correctly move each element through move-construction (when // initializing the owning class), the standard defines the type trait in // terms of a variable declaration, where the move construction syntax is // invalid. #endif } // close package namespace } // close enterprise namespace namespace bsl { // ==================================== // struct is_nothrow_move_constructible // ==================================== template <class t_TYPE> struct is_nothrow_move_constructible : BloombergLP::bslmf::IsNothrowMoveConstructible_Impl<t_TYPE>::type { // This 'struct' template implements a metafunction to determine whether // the (template parameter) 't_TYPE' has a no-throw move constructor. This // 'struct' derives from 'bsl::true_type' if the 't_TYPE' has a no-throw // move constructor, and from 'bsl::false_type' otherwise. This // metafunction has the same syntax as the 'is_nothrow_move_constructible' // metafunction defined in the C++11 standard [meta.unary.prop]; on C++03 // platforms, however, this metafunction can automatically determine the // value for trivially copyable types (including scalar types), for // reference types, and for class types associating with the // 'bsl::is_nothrow_move_constructible' trait using the // 'BSLMF_NESTED_TRAIT_DECLARATION' macro. To support other no-throw move // constructible types, this template should be specialized to inherit from // 'bsl::true_type'. Note that cv-qualified user defined types are rarely // no-throw move constructible unless they are also trivially copyable, so // there are no cv-qualified partial specializations of this trait. }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES template <class t_TYPE> BSLS_KEYWORD_INLINE_VARIABLE constexpr bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<t_TYPE>::value; // This template variable represents the result value of the // 'bsl::is_nothrow_move_constructible' metafunction. #endif } // close namespace bsl #endif // ---------------------------------------------------------------------------- // Copyright 2019 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 ----------------------------------