// bslmf_invokeresult.h -*-C++-*- #ifndef INCLUDED_BSLMF_INVOKERESULT #define INCLUDED_BSLMF_INVOKERESULT #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Determine the result type of an invocable expression. // //@CLASSES: // bsl::invoke_result: Metafunction to determine invocation result type // bslmf::InvokeResultDeductionFailed: Returned on failed result deduction // //@MACROS: // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS: defined if SFINAE-friendly // //@SEE_ALSO: bslstl_invoke // //@DESCRIPTION: This component provides a metafunction 'bsl::invoke_result' // that determines, at compile time, the type returned by invoking a callable // type, including pointer-to-function, pointer-to-member function, // pointer-to-member object (returns the object type), or functor class, and a // class 'bslmf::InvokeResultDeductionFailed' that is returned when the // invocation return type cannot be determined (C++03 only). For a set of // types 'F', 'T1', 'T2', and 'T3', 'bsl::invoke_result<F, T1, t2, T3>::type' // is roughly the type of the return value obtained by calling an object of // type 'F' with arguments of type 'T1', 'T2', and 'T3', respectively. // However, 'invoke_result' goes beyond function-like objects and deduces a // return type if 'F' is a pointer to function member or data member of some // class 'C' and 'T1' is a type (derived from) 'C', pointer to 'C', or // smart-pointer to 'C'. (See precise specification, below). // // The interface and functionality of 'bsl::invoke_result' is intended to be // identical to that of the C++17 metafunction, 'std::invoke_result' except // that invalid argument lists are detected in C++11 and later, but not in // C++03. In C++03, invalid arguments lists will result in a compilation error // (instead of simply missing 'type') in the remaining cases. Some other // functionality is lost when compiling with a C++03 compiler -- see the // precise specification, below. // ///C++17 Semantics Detection ///------------------------- // This component defines the macro // 'BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS' if 'bsl::invoke_result' behaves // according to the C++17 specification of 'std::invoke_result', which is // elaborated below. This macro is defined as long as the compiler supports // the 'decltype' specifier, which is generally available in C++11 and later // compilation modes. // ///Precise specification ///--------------------- // The C++11 and C++14 standard defines the pseudo-expression // _INVOKE_ '(f, t1, t2, ..., tN)', as follows: // //: o '(t1.*f)(t2, ..., tN)' when 'f' is a pointer to a member function of a //: class 'T' and 't1' is an object of type 'T' or a reference to an object //: of type 'T' or a reference to an object of a type derived from 'T'; //: o '((*t1).*f)(t2, ..., tN)' when 'f' is a pointer to a member function of //: a class 'T' and 't1' is not one of the types described in the previous //: item; //: o 't1.*f' when 'N == 1' and 'f' is a pointer to member data of a class 'T' //: and 't1' is an object of type 'T' or a reference to an object of type //: 'T' or a reference to an object of a type derived from 'T'; //: o '(*t1).*f' when 'N == 1' and 'f' is a pointer to member data of a class //: 'T' and 't1' is not one of the types described in the previous item; //: o 'f(t1, t2, ..., tN)' in all other cases. // // Given types 'F', 'T1', 'T2', ..., 'TN' corresponding to the expressions // 'f', 't1', 't2', ..., 'tN' in the definition of _INVOKE_, the type produced // by 'bslmf::ResultType<F, T1, T2, ..., TN>::type' is generally the type of // the psuedo-expression _INVOKE_ '(f, t1, t2, ..., tN)', with some // limitations in C++03, as described below. // // Because C++03 does not support 'decltype', there are circumstances in which // 'bsl::invoke_result' is not able to deduce the return type of an invocable // object of class type (i.e., a functor). If 'R' is the type of the _INVOKE_ // expression, then ideally 'type' is 'R'. However the C++03 version of // 'bsl::invoke_result' determines 'type' as follows: // //: 1 If there exists a user-defined specialization of //: 'bsl::invoke_result<F, T1, T2, ... TN>', then 'type' is determined by the //: specialization, regardless of correctness. (This rule is true of C++11 //: and later, as well.) //: 2 Otherwise, if 'F' is a function type, pointer to function type, pointer //: to member function type, pointer to member object type, or reference to //: any of these (i.e, 'F' is anything other than a class type or reference //: to class type), then 'type' is 'R'. //: 3 Otherwise, if 'R' is o a fundamental type, o a pointer to (possibly //: cv-qualified) 'void' or fundamental type, o an lvalue reference to any of //: the above types (possibly cv-qualified), o 'bsl::nullptr_t', or o 'void', //: then 'type' is 'R'. //: 4 Otherwise, if 'F' is a class type with member 'result_type', then 'type' //: is 'F::result_type'. Note that 'bsl::invoke_result' cannot deduce //: different result types for different overloads of 'operator()' in this //: case. //: 5 Otherwise, if 'F' is a class type with member type 'ResultType', then //: 'type' is 'F::ResultType'. Note that 'bsl::invoke_result' cannot deduce //: different result types for different overloads of 'operator()' in this //: case. //: 6 Otherwise, 'type' is 'bslmf::InvokeResultDeductionFailed'. The benefit //: of this placeholder over a compilation error is that 'invoke_result' is //: often used in a context where the return value will eventually be //: discarded. Thus, generating a useless type is often harmless. In cases //: where it is not harmless, the placeholder type will almost certainly //: result in a compilation error in the surrounding code. // // If the callable type is a pointer-to-member (data or function), invalid // argument lists are not detected. Thus, there is a small chance that invalid // code will compile successfully, though it is hard to see now this would be // harmful, since determining the return type of an expression is not very // useful if the expression is not eventually evaluated, which will certainly // produce the expected compilation error for invalid argument lists. // ///Usage Example ///------------- // Suppose we want to create a wrapper that executes an invocable object and // sets a 'done' flag. The 'done' flag will not be set if the invocation // exits via an exception. The wrapper takes an invocable 'f' and an argument // 'x' and evaluates 'f(x)', returning the result. In the absence of C++14 // automatically-deduced function return declarations, we use // 'bsl::invoke_result' to deduce the return type of 'f(x)'. // // First, we write the wrapper template as follows: //.. // template <class FT, class XT> // typename bsl::invoke_result<FT, XT>::type // invokeAndSetFlag(bool *done, FT f, XT x) // // Return 'f(x)' and set '*done' to true if no exception. // { // typedef typename bsl::invoke_result<FT, XT>::type ResultType; // *done = false; // Clear flag in case of exception // ResultType result = f(x); // *done = true; // Set flag on success // return result; // } //.. // Note that additional metaprogramming would be required to make this // template work for return type 'void'; such metaprogramming is beyond the // scope of this usage example. // // Then we define a couple of simple functors to be used with the wrapper. // The first functor is a simple template that triples its invocation // argument: //.. // template <class t_TP> // struct Triple { // // Functor that triples its argument. // // t_TP operator()(t_TP v) const { return static_cast<t_TP>(v * 3); } // // Return three times the specified 'v' value. // }; //.. // Next, we define a second functor that returns an enumerator 'ODD' or // 'EVEN', depending on whether its argument is exactly divisible by 2. Since // the return type is not a fundamental type, this functor indicates its // return type using the 'ResultType' idiom: //.. // enum EvenOdd { e_EVEN, e_ODD }; // // struct CalcEvenOdd { // // Functor that determines whether its argument is odd or even. // // typedef EvenOdd ResultType; // // EvenOdd operator()(int i) const { return (i & 1) ? e_ODD : e_EVEN; } // // Return 'e_ODD' if the specified 'i' is odd; otherwise return // // 'e_EVEN' // }; //.. // Finally, we can invoke these functors through our wrapper: //.. // int main() // // Run the usage example. // { // bool done = false; // // Triple<short> ts = {}; // short r0 = invokeAndSetFlag(&done, ts, short(9)); // assert(done && 27 == r0); // // CalcEvenOdd ceo = {}; // done = false; // EvenOdd r1 = invokeAndSetFlag(&done, ceo, 5); // assert(done && e_ODD == r1); // // done = false; // EvenOdd r2 = invokeAndSetFlag(&done, ceo, 8); // assert(done && e_EVEN == r2); // // return 0; // } //.. #include <bslscm_version.h> #include <bslmf_addconst.h> #include <bslmf_addlvaluereference.h> #include <bslmf_addpointer.h> #include <bslmf_addrvaluereference.h> #include <bslmf_addvolatile.h> #include <bslmf_assert.h> #include <bslmf_decay.h> #include <bslmf_enableif.h> #include <bslmf_functionpointertraits.h> #include <bslmf_isaccessiblebaseof.h> #include <bslmf_isclass.h> #include <bslmf_isconvertible.h> #include <bslmf_islvaluereference.h> #include <bslmf_ismemberobjectpointer.h> #include <bslmf_isreference.h> #include <bslmf_isreferencewrapper.h> #include <bslmf_isrvaluereference.h> #include <bslmf_isvoid.h> #include <bslmf_memberfunctionpointertraits.h> #include <bslmf_memberpointertraits.h> #include <bslmf_movableref.h> #include <bslmf_removecv.h> #include <bslmf_resulttype.h> #include <bslmf_tag.h> #include <bslmf_voidtype.h> #include <bsls_compilerfeatures.h> #include <bsls_nullptr.h> #include <bsls_platform.h> #if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // Include version that can be compiled with C++03 // Generated on Thu Feb 16 18:08:36 2023 // Command line: sim_cpp11_features.pl bslmf_invokeresult.h # define COMPILING_BSLMF_INVOKERESULT_H # include <bslmf_invokeresult_cpp03.h> # undef COMPILING_BSLMF_INVOKERESULT_H #else #if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) \ && !(defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION == 1800) // The implementation of C++17 semantics in this component depends upon the // use of 'decltype' for expression SFINAE. MSVC 2013 (which has version // number 1800) claims to support 'decltype', but does not have a sufficiently // functional implementation of expression sfinae to enable C++17 semantics. #define BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS 1 #endif namespace BloombergLP { namespace bslmf { // ========================================== // class template InvokeResultDeductionFailed // ========================================== struct InvokeResultDeductionFailed { // When 'invoke_result' cannot deduce the actual return type of a functor // (in C++03 mode), it yields this type as a placeholder. The advantage of // using this placeholder instead of a compilation failure (e.g., using a // static assert) is that the return type of an INVOKE() operation is // often discarded, so our failure to deduce the return type is often // harmless. Since 'InvokeResultDeductionFailed' is a return type, it must // be convertible from the actual return type; this conversion is // accomplished by means of a constructor that makes it convertible from // *any* type. // CREATORS template <class t_TYPE> InvokeResultDeductionFailed(const t_TYPE&) { } // Convert from an arbitrary type. The actual argument value is // discarded. }; #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 template <class t_FN, class... t_ARGTYPES> struct InvokeResult_BaseCalcUtil; // Forward declaration #endif } // close package namespace } // close enterprise namespace // ============================ // class template invoke_result // ============================ namespace bsl { #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 template <class t_FN, class... t_ARGTYPES> class invoke_result : public BloombergLP::bslmf::InvokeResult_BaseCalcUtil<t_FN, t_ARGTYPES...>:: BaseType { // This class is a metafunction that conditionally provides a 'type' member // that is the type resulting from invoking an object of the specified // 't_FN' template parameter with arguments of the specified 't_ARGTYPES' // template parameters. More precisely, given types 'F', 'T1', 'T2', ..., // 'TN' corresponding to expressions 'f', 't1', 't2', ..., 'tN', // 'bslmf::ResultType<F, T1, T2, ..., TN>::type' is usually the type of the // psuedo-expression _INVOKE_ '(f, t1, t2, ..., tN)', as defined in section // [func.rquire] of the C++11 standard. If the compiler supports C++11 // 'decltype' and the psuedo-expression _INVOKE_ '(f, t1, t2, ..., tN)' is // not well-formed, this class provides no 'type' member. If 't_FN' is a // class (functor) type and the compiler doesn't support C++11 'decltype', // the return type is automatically deduced for fundamental types, 'void', // pointers or references to those, or 'bsl::nullptr_t' and is deduced by // 'bslmf::ResultType<t_FN>::type' otherwise. If deduction fails, this // metafunction yields 'bslmf::InvokeResultDeductionFailed'. See // component-level documentation for more detail. ///Implementation Note ///- - - - - - - - - - // If, by the rules outlined above in the class documentation, this type // defines a member 'type' typedef, that typedef comes from the // 'bslmf::InvokeResult_BaseCalcUtil' specialization from which this class // inherits. }; #endif } // close namespace bsl // ============================================================================ // TEMPLATE IMPLEMENTATIONS // ============================================================================ namespace BloombergLP { namespace bslmf { #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 template <bool t_IS_FUNCPTR, bool t_IS_MEMFUNCPTR, bool t_IS_MEMOBJPTR, class t_FN, class... t_ARGTYPES> struct InvokeResult_Imp; // Forward declaration // ========================================= // struct template InvokeResult_BaseCalcUtil // ========================================= template <class t_FN, class... t_ARGTYPES> struct InvokeResult_BaseCalcUtil { // This component-private utility 'struct' template provides a nested // typedef, 'BaseType', which is a class type that itself provides a nested // typedef 'type' that is the type of the 'INVOKE(fn, args...)' expression // given 'fn' is an object of the specified 't_FN' type and 'args...' are // objects of the specified 't_ARGTYPES...' types. If the // 'INVOKE(fn, args...)' expression is not well-formed, 'BaseType' provides // no such nested typedef. private: // PRIVATE TYPES typedef typename bslmf::MovableRefUtil::Decay<t_FN>::type F; // Remove references and cv-qualifiers from 't_FN', and decay function // types and array types to pointers. In C++03, treat // 'bslmf::MovableRef<t_T>' as a (movable) reference-qualified 't_T'. enum { k_IS_FUNCPTR = BloombergLP::bslmf::IsFunctionPointer<F>::value, k_IS_MEMFUNCPTR= BloombergLP::bslmf::IsMemberFunctionPointer<F>::value, k_IS_MEMOBJPTR = bsl::is_member_object_pointer<F>::value }; typedef typename bsl::conditional<k_IS_FUNCPTR || k_IS_MEMFUNCPTR || k_IS_MEMOBJPTR, F, t_FN>::type FwdFn; // 'FwdFn' is the type forwarded to 'InvokeResult_Imp'. It is 'F' // (a.k.a., 'decay_t<t_FN>') if 'F' is a function pointer or // pointer-to-member and 't_FN' otherwise. public: // TYPES typedef typename BloombergLP::bslmf::InvokeResult_Imp<k_IS_FUNCPTR, k_IS_MEMFUNCPTR, k_IS_MEMOBJPTR, FwdFn, t_ARGTYPES...> BaseType; // In C++11 and later, conditionally provides a nested typedef 'type' // that is the type returned by the expression _INVOKE_ '(f, args...)', // where 'f' is an object of type 't_FN' and 'args...' is a list of // object of types 't_ARGTYPES...', if the expression is well formed. // In C++03, provide a nested typed 'type' that is the type returned by // the same invoke expression if the type can be deduced, and is // 'InvokeResultDeductionFailed' otherwise. Note that in C++11 and // later, 'type' is never 'InvokeResultDeductionFailed'. }; #endif // =============================== // struct InvokeResult_VoidChecker // =============================== struct InvokeResult_VoidChecker : Tag<true> { // Empty type used to detect void expressions. The size of this type is // the same as 'bslmf::Tag<1>'. }; template <class t_TYPE> typename bsl::enable_if<!bsl::is_void<t_TYPE>::value, Tag<false> >::type operator,(const t_TYPE&, InvokeResult_VoidChecker); // Return 'InvokeResult_VoidChecker()' if the left argument is of type // cv-'void'; otherwise 'bslmf::Tag<false>()'. This overload of the comma // operator is declared but not defined, and is intended to be used in // metafunctions in an unevaluated context to detect void expressions. For // any non-void expression 'expr', '(expr,InvokeResult_VoidChecker())', // will match this overload and produce a result of type // 'bslmf::Tag<false>'. However, 'const t_TYPE&' will not match 'void', so // if 'expr' is a void expression, the built-in comma operator is matched // and the result will have type 'InvokeResult_VoidChecker' (i.e., the // second argument). // // Note that Sun CC incorrectly matches this overload for a void // expression, then fails hard. The 'enable_if' prevents this match for // Sun CC and any other compilers that may similarly match 'void' and is // harmless for compilers that don't. struct InvokeResult_Index { // Metafunction helpers for deducing the return type of an expression. enum { // Enumeration of possible return types. e_VOID, e_BOOL, e_CHAR, e_SCHAR, e_UCHAR, e_CHAR8_T, e_WCHAR_T, e_CHAR16_T, e_CHAR32_T, e_SHORT, e_USHORT, e_INT, e_UNSIGNED, e_LONG, e_ULONG, e_LONG_LONG, e_ULONG_LONG, e_FLOAT, e_DOUBLE, e_LONG_DOUBLE, // Pointer to void is special among pointers because it cannot be // dereferenced. e_VOIDPTR, e_CONST_VOIDPTR, e_VOLATILE_VOIDPTR, e_CONST_VOLATILE_VOIDPTR, e_NULLPTR_T, e_POINTER, // Any pointer type other than 'void *' or 'nullptr_t' e_OTHER // Anything other than above }; // CLASS METHODS static bslmf::Tag<e_BOOL> fromVal(bool& ); static bslmf::Tag<e_CHAR> fromVal(char& ); static bslmf::Tag<e_SCHAR> fromVal(signed char& ); static bslmf::Tag<e_UCHAR> fromVal(unsigned char& ); #ifdef BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE static bslmf::Tag<e_CHAR8_T> fromVal(char8_t& ); #endif static bslmf::Tag<e_WCHAR_T> fromVal(wchar_t& ); #ifdef BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES static bslmf::Tag<e_CHAR16_T> fromVal(char16_t& ); static bslmf::Tag<e_CHAR32_T> fromVal(char32_t& ); #endif static bslmf::Tag<e_SHORT> fromVal(short& ); static bslmf::Tag<e_USHORT> fromVal(unsigned short& ); static bslmf::Tag<e_INT> fromVal(int& ); static bslmf::Tag<e_UNSIGNED> fromVal(unsigned& ); static bslmf::Tag<e_LONG> fromVal(long& ); static bslmf::Tag<e_ULONG> fromVal(unsigned long& ); static bslmf::Tag<e_LONG_LONG> fromVal(long long& ); static bslmf::Tag<e_ULONG_LONG> fromVal(unsigned long long& ); static bslmf::Tag<e_FLOAT> fromVal(float& ); static bslmf::Tag<e_DOUBLE> fromVal(double& ); static bslmf::Tag<e_LONG_DOUBLE> fromVal(long double& ); static bslmf::Tag<e_VOIDPTR> fromVal(void *& ); static bslmf::Tag<e_CONST_VOIDPTR> fromVal(const void *& ); static bslmf::Tag<e_VOLATILE_VOIDPTR> fromVal(volatile void *& ); static bslmf::Tag<e_CONST_VOLATILE_VOIDPTR> fromVal(const volatile void*&); static bslmf::Tag<e_NULLPTR_T> fromVal(bsl::nullptr_t&); template <class t_TP> static bslmf::Tag<e_POINTER> fromVal(t_TP *&); template <class t_TP> static bslmf::Tag<e_OTHER> fromVal(t_TP&); // Return a tag type representing the argument type. These functions // are declared but not defined and are intended to be used in an // unevaluated context (e.g., within 'sizeof') to convert an expression // into a compile-time enumeration constant. }; template <int t_INDEX> struct InvokeResult_Type; // Metafunction to convert a type index back to a type. For each // specialization of this struct, the 'type' member will be the type // corresponding to 'index'. For example, if 'index' is 'e_UCHAR', then // 'InvokeResult_Type<index>::type' is 'unsigned char'. // Turn off bde_verify warnings for "Declaration without tag". Pedantically, // every 'type' declared in a metafunction should have the tag '// TYPES', but // that breaks up the clean 3-line declaration of each specialization, making // the pattern harder to for the eye to follow. // BDE_VERIFY pragma: push // BDE_VERIFY pragma: -KS00 template <> struct InvokeResult_Type<InvokeResult_Index::e_VOID> { typedef void type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_BOOL> { typedef bool type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_CHAR> { typedef char type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_SCHAR> { typedef signed char type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_UCHAR> { typedef unsigned char type; }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_UTF8_CHAR_TYPE template <> struct InvokeResult_Type<InvokeResult_Index::e_CHAR8_T> { typedef char8_t type; }; #endif template <> struct InvokeResult_Type<InvokeResult_Index::e_WCHAR_T> { typedef wchar_t type; }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_UNICODE_CHAR_TYPES template <> struct InvokeResult_Type<InvokeResult_Index::e_CHAR16_T> { typedef char16_t type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_CHAR32_T> { typedef char32_t type; }; #endif template <> struct InvokeResult_Type<InvokeResult_Index::e_SHORT> { typedef short type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_USHORT> { typedef unsigned short type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_INT> { typedef int type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_UNSIGNED> { typedef unsigned type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_LONG> { typedef long type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_ULONG> { typedef unsigned long type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_LONG_LONG> { typedef long long type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_ULONG_LONG> { typedef unsigned long long type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_FLOAT> { typedef float type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_DOUBLE> { typedef double type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_LONG_DOUBLE> { typedef long double type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_VOIDPTR> { typedef void *type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_CONST_VOIDPTR> { typedef const void *type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_VOLATILE_VOIDPTR> { typedef volatile void *type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_CONST_VOLATILE_VOIDPTR> { typedef const volatile void *type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_NULLPTR_T> { typedef bsl::nullptr_t type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_POINTER> { typedef void *type; }; template <> struct InvokeResult_Type<InvokeResult_Index::e_OTHER> { typedef InvokeResultDeductionFailed type; }; // Re-enable warnings for "Declaration without tag" // BDE_VERIFY pragma: pop struct InvokeResult_ImpUtils { // Utility metaprogramming functions inherited by other metaprogramming // classes. // TYPES struct AnyLvalue { // Type convertible from any lvalue type. Used for overload resolution // in metafunctions. // CREATORS template <class t_TP> AnyLvalue(volatile t_TP&); // (Declared but not defined) Convert from any lvalue argument. }; struct AnyRvalue { // Type convertible from any rvalue type. Used for overload resolution // in metafunctions. // CREATORS #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_TP> AnyRvalue( t_TP&&, typename bsl::enable_if<bsl::is_rvalue_reference<t_TP&&>::value, int>::type = 0); // (Declared but not defined) Convert from any rvalue argument. #else template <class t_TP> AnyRvalue(t_TP); // (Declared but not defined) Convert from any rvalue argument. // This constructor will also match lvalue arguments, but is used // in a context where 'AnyLValue' is a better conversion path. #endif }; // CLASS METHODS #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class t_SOME_TYPE> static typename bsl::add_rvalue_reference<t_SOME_TYPE>::type myDeclval(); // Return a reference to the specified 't_SOME_TYPE' template parameter // type; if 't_SOME_TYPE' is an rvalue, then the returned reference is // an rvalue reference. This function is declared but not defined and // is intended to be called in an unevaluated context. Because there // is no definition, the available constructors for 't_SOME_TYPE' are // irrelevant. #else template <class t_SOME_TYPE> static t_SOME_TYPE myDeclval(); // Return an object of the specified 't_SOME_TYPE' template parameter // type. This function is declared but not defined and is intended to // be called in an unevaluated context. Because there is no // definition, the available constructors for 't_SOME_TYPE' are // irrelevant. #endif static bslmf::Tag<false> checkLvalue(AnyRvalue, ...); static bslmf::Tag<true > checkLvalue(AnyLvalue, int); // (Declared but not defined) Return 'bslmf::Tag<false>()' if the // first argument is an rvalue and 'bslmf::Tag<true>()' if it is // lvalue. In actual use, the second argument is always a literal // 'int', which causes the second overload to be preferred in case of // ambiguity. template <class t_TP> static bslmf::Tag<false> checkConst(t_TP&); template <class t_TP> static bslmf::Tag<true> checkConst(const t_TP&); // (Declared but not defined) Return 'bslmf::Tag<true>()' if the // argument is 'const'-qualified and 'bslmf::Tag<false>()' otherwise. template <class t_TP> static bslmf::Tag<false> checkVolatile(t_TP&); template <class t_TP> static bslmf::Tag<false> checkVolatile(const t_TP&); template <class t_TP> static bslmf::Tag<true> checkVolatile(volatile t_TP&); template <class t_TP> static bslmf::Tag<true> checkVolatile(const volatile t_TP&); // (Declared but not defined) Return 'bslmf::Tag<true>()' if the // argument is 'volatile'-qualified and 'bslmf::Tag<false>()' // otherwise. Note that if 't_TP' is both const- and // volatile-qualified, it will not match 'volatile t_TP&', hence the // need for the const overloads. template <class t_TP> static t_TP& uncv(const t_TP&); template <class t_TP> static t_TP& uncv(const volatile t_TP&); // (Declared but not defined) Return the argument, with cv-qualifiers // removed. template <class t_TP> static t_TP& unpoint(t_TP&); template <class t_TP> static const t_TP& unpoint(const t_TP&); template <class t_TP> static typename bsl::enable_if<!bsl::is_void<t_TP>::value, t_TP>::type& unpoint(t_TP *&); template <class t_TP> static typename bsl::enable_if<!bsl::is_void<t_TP>::value, t_TP>::type& unpoint(t_TP *const&); template <class t_TP> static typename bsl::enable_if<!bsl::is_void<t_TP>::value, t_TP>::type& unpoint(t_TP *volatile&); template <class t_TP> static typename bsl::enable_if<!bsl::is_void<t_TP>::value, t_TP>::type& unpoint(t_TP *const volatile&); // If the argument type 't_TP' is pointer to type 'X', where 'X' is not // cv-'void', return a reference to 'X'; otherwise return a reference // to 't_TP'. Note that these functions are declared but not defined // and are intended to be called only in an unevaluated context. }; template <class t_UNQUAL_TYPE, bool t_IS_CONST, bool t_IS_VOLATILE, bool t_IS_LVALUE> struct InvokeResult_AddCVRef { // Starting with type, 't_UNQUAL_TYPE', generate a new type by applying the // following steps in order: // //: 1 If the specified 't_IS_CONST' parameter is true, apply //: 'bsl::add_const'; otherwise leave unchanged. //: 2 If the specified 't_IS_VOLATILE' parameter is true, apply //: 'bsl::add_volatile'; otherwise leave unchanged. //: 3 If the specified 't_IS_LVALUE' parameter is true, apply //: 'bsl::add_lvalue_reference'; otherwise leave unchanged. // // Set the 'type' member to the resulting type. private: // PRIVATE TYPES typedef typename bsl::conditional<t_IS_CONST, typename bsl::add_const<t_UNQUAL_TYPE>::type, t_UNQUAL_TYPE>::type CQualType; typedef typename bsl::conditional<t_IS_VOLATILE, typename bsl::add_volatile<CQualType>::type, CQualType>::type CVQualType; public: // TYPES typedef typename bsl::conditional< t_IS_LVALUE, typename bsl::add_lvalue_reference<CVQualType>::type, CVQualType>::type type; }; #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 #ifndef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <bool /* IS_VOID */, class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorDeduction : InvokeResult_ImpUtils { // Deduce return type of 't_FN(t_ARGTYPES...)'. This template is // instantiated only when 't_FN' is of class type (i.e., a functor). This // primary template is selected when 't_FN(t_ARGTYPES...)' is not 'void'. // Note that this template is not defined in C++11 mode (if 'decltype' // exists). typedef typename bsl::decay<t_FN>::type F; // Remove references and cv-qualifiers from 't_FN', and decay function // types and array types to pointers. enum { // In an unevaluated context ('BSLMF_TAG_TO_INT'), "invoke" // 'myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)' and use overloading // to deduce the type and other attributes of the return value. k_INDEX = BSLMF_TAG_TO_INT(InvokeResult_Index::fromVal( uncv(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)))), k_IS_POINTER = (k_INDEX == InvokeResult_Index::e_POINTER), k_IS_LVALUE = BSLMF_TAG_TO_INT( checkLvalue(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...), 0)), k_IS_CONST_PTR = k_IS_POINTER && BSLMF_TAG_TO_INT(checkConst( myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...))), k_IS_VOLATILE_PTR = k_IS_POINTER && BSLMF_TAG_TO_INT(checkVolatile(myDeclval<t_FN>()( myDeclval<t_ARGTYPES>()...))), k_TARGET_INDEX = BSLMF_TAG_TO_INT(InvokeResult_Index::fromVal( uncv(unpoint(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...))))), k_IS_CONST_TARGET = BSLMF_TAG_TO_INT(checkConst( unpoint(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)))), k_IS_VOLATILE_TARGET = BSLMF_TAG_TO_INT(checkVolatile( unpoint(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)))), k_CANT_DEDUCE_TYPE = (k_TARGET_INDEX == (int)InvokeResult_Index::e_OTHER) }; typedef typename bsl::conditional< ! k_CANT_DEDUCE_TYPE, typename InvokeResult_Type<k_TARGET_INDEX>::type, typename ResultType<F,InvokeResultDeductionFailed>::type >::type UnqualTargetType; // The deduced result after stripping off pointer, reference, and // cv-qualifiers. The 'TARGET_INDEX' indicates the fundamental type of // the target result. If the target could not be deduced (i.e., // 'TARGET_INDEX == e_OTHER), then attempt to find the result by // looking for a 'result_type' or 'ResultType' alias in 't_FN'; failing // that, use 'InvokeResultDeductionFailed'. typedef typename InvokeResult_AddCVRef<UnqualTargetType, static_cast<bool>(k_IS_CONST_TARGET) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE), static_cast<bool>(k_IS_VOLATILE_TARGET) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE), false>::type CVQualTargetType; // The deduced target after adding back previously-stripped cv // qualifiers, if any. Note that if the expression yielded a pointer // type, these cv qualifiers apply to the target of the pointer, not // the pointer itself. typedef typename bsl::conditional<static_cast<bool>(k_IS_POINTER) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE), typename bsl::add_pointer<CVQualTargetType>::type, CVQualTargetType>::type UnqualType; // The deduced result after adding back previously-stripped pointers, // if any. typedef typename InvokeResult_AddCVRef< UnqualType, static_cast<bool>(k_IS_CONST_PTR) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE), static_cast<bool>(k_IS_VOLATILE_PTR) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE), static_cast<bool>(k_IS_LVALUE) && ! static_cast<bool>(k_CANT_DEDUCE_TYPE)>::type Qtype; // The deduced result after adding back previously-stripped cv // qualifiers and references. Note that if the result is a pointer, // the cv qualifiers apply to the pointer, not to the target. typedef typename bsl::conditional<static_cast<bool>(k_IS_LVALUE), Qtype, typename bsl::remove_cv<Qtype>::type>::type type; // The final deduced result type. If the type is not a reference, // top-level cv qualifiers are stripped off. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorDeduction<true /* IS_VOID */, t_FN, t_ARGTYPES...> { // Deduce return type of 't_FN(t_ARGTYPES...)'. This template is // instantiated only when 't_FN' is of class type (i.e., a functor). This // specialization is selected when 't_FN(t_ARGTYPES...)' is cv-'void'. typedef void type; }; #endif // !BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS #endif template <class t_MEMOF_CLASS, class t_ARG_TYPE, bool t_IS_DERIVED = bsl::is_convertible< typename bsl::decay<t_ARG_TYPE>::type *, typename bsl::decay<t_MEMOF_CLASS>::type *>::value> struct InvokeResult_MemPtrArgQualifiers { // This metafunction determines which cv qualifiers and reference // qualifiers should be propagated from the first argument of // 'invoke_result'. This primary template is instantiated when // 't_ARG_TYPE' is the same or is derived from 't_MEMOF_CLASS'. The // constant 'k_IS_LVALUE' is true iff 't_ARG_TYPE' is an lvalue reference; // the constant 'k_IS_CONST' is true iff 't_ARG_TYPE' is const-qualified; // and the constant 'k_IS_VOLATILE' is true iff 't_ARG_TYPE' is // volatile-qualified. // TYPES enum { k_IS_LVALUE = bsl::is_lvalue_reference<t_ARG_TYPE>::value, k_IS_CONST = bsl::is_const< typename bsl::remove_reference<t_ARG_TYPE>::type>::value, k_IS_VOLATILE = bsl::is_volatile< typename bsl::remove_reference<t_ARG_TYPE>::type>::value }; }; template <class t_MEMOF_CLASS, class t_ARG_TYPE> struct InvokeResult_MemPtrArgQualifiers<t_MEMOF_CLASS, t_ARG_TYPE, false> : InvokeResult_ImpUtils { // This metafunction determines which cv qualifiers and reference // qualifiers should be propagated from the first argument of // 'invoke_result'. // // This specialization is instantiated when 't_ARG_TYPE' is not derived // from 't_MEMOF_CLASS' and is assumed to be a pointer or smart pointer // type. If type 'A' is the result of dereferencing an object of type // 't_ARG_TYPE', then the constant 'k_IS_LVALUE' is true iff 'A' is an // lvalue reference; the constant 'k_IS_CONST' is true iff 'A' is a // const-qualified reference; and the constant 'k_IS_VOLATILE' is true iff // 'A' is a volatile-qualified reference. #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES private: // CLASS METHODS template <class t_TP> static t_TP& tolvalue(t_TP&&); // (Declared but not defined.) Return an lvalue reference // corresponding of the specified 't_TP' type, which is deduced from // the specified unnamed argument. If the argument is an lvalue, the // return type is identical to the argument type. If the argument is // an rvalue, the return type is an lvalue to the argument type with // the same cv qualifiers. This function is useful for avoiding too // many redundant overloads in metafunctions that determine cv // qualifications, etc. public: // TYPES enum {k_IS_LVALUE = BSLMF_TAG_TO_INT(checkLvalue(*myDeclval<t_ARG_TYPE>(), 0)), k_IS_CONST = BSLMF_TAG_TO_INT(checkConst(tolvalue(*myDeclval<t_ARG_TYPE>()))), k_IS_VOLATILE = BSLMF_TAG_TO_INT( checkVolatile(tolvalue(*myDeclval<t_ARG_TYPE>())))}; #else public: // TYPES enum { k_IS_LVALUE = BSLMF_TAG_TO_INT(checkLvalue(*myDeclval<t_ARG_TYPE>(), 0)), // In C++03, cv qualifiers are discarded from rvalues. k_IS_CONST = k_IS_LVALUE && BSLMF_TAG_TO_INT(checkConst(*myDeclval<t_ARG_TYPE>())), k_IS_VOLATILE = k_IS_LVALUE && BSLMF_TAG_TO_INT(checkVolatile( *myDeclval<t_ARG_TYPE>())) }; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES }; #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorImp; // Forward declaration template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FuncPtrImp; // Forward declaration template <class t_FN, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImp; // Forward declaration template <class t_FN, class... t_ARGTYPES> struct InvokeResult_MemObjPtrImp; // Forward declaration // ================================ // struct template InvokeResult_Imp // ================================ template <bool t_IS_FUNCPTR, bool t_IS_MEMFUNCPTR, bool t_IS_MEMOBJPTR, class t_FN, class... t_ARGTYPES> struct InvokeResult_Imp : InvokeResult_FunctorImp<void, t_FN, t_ARGTYPES...> { // This component-private, partial 'struct' template specialization // provides the implementation of 'InvokeResult_Imp' for types that are // neither function pointers, pointers to member functions, nor pointers to // member objects. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_Imp<true /* t_IS_FUNCPTR */, false, false, t_FN, t_ARGTYPES...> : InvokeResult_FuncPtrImp<void, t_FN, t_ARGTYPES...> { // This component-private, partial 'struct' template specialization // provides the implementation of 'InvokeResult_Imp' for function pointer // types. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_Imp<false, true /* t_IS_MEMFUNCPTR */, false, t_FN, t_ARGTYPES...> : InvokeResult_MemFuncPtrImp<t_FN, t_ARGTYPES...> { // This component-private, partial 'struct' template specialization // provides the implementation of 'InvokeResult_Imp' for pointer to member // function types. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_Imp<false, false, true /* t_IS_MEMOBJPTR */, t_FN, t_ARGTYPES...> : InvokeResult_MemObjPtrImp<t_FN, t_ARGTYPES...> { // This component-private, partial 'struct' template specialization // provides the implementation of 'InvokeResult_Imp' for pointer to member // object types. }; // ======================================= // struct template InvokeResult_FunctorImp // ======================================= #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorImp { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is neither // a pointer-to-function, pointer-to-member-function, nor // pointer-to-member-object type, and the 'INVOKE(fn, args...)' expression, // is *not* well-formed given 'fn' is an object of the specified 't_FN' // type and 'args...' are objects of the specified 't_ARGTYPES...' types. // The 'INVOKE(fn, args...)' expression in this case is 'fn(args...)'. // Note that this 'struct' does not provide a 'type' typedef. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorImp< typename bslmf::VoidType<decltype(InvokeResult_ImpUtils::myDeclval<t_FN>()( InvokeResult_ImpUtils::myDeclval<t_ARGTYPES>()...))>::type, t_FN, t_ARGTYPES...> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is neither // a pointer-to-function, pointer-to-member-function, nor // pointer-to-member-object type, and the 'INVOKE(fn, args...)' expression // is well-formed given 'fn' is an object of the specified 't_FN' type and // 'args...' are objects of the specified 't_ARGTYPES...' types. The // 'INVOKE(fn, args...)' expression in this case is 'fn(args...)'. // TYPES typedef decltype(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)) type; // For C++11 and later, the type of the 'INVOKE(fn, args...)' // expression given 'fn' is an object of the specified 't_FN' type and // 'args...' are objects of the specified 't_ARGTYPES...' types. The // 'INVOKE(fn, args...)' expression in this case is 'fn(args...)'. }; #else // ! BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FunctorImp : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++03 when 't_FN' is neither a // pointer-to-function, pointer-to-member-function, nor // pointer-to-member-object type. // TYPES enum { // Determine if 'myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)' is a // void expression by invoking the overloaded comma operator using a // 'InvokeResult_VoidChecker' as the second argument. If the // expression is of void type, then the built-in comma operator will // yield 'InvokeResult_VoidChecker', otherwise the overloaded comma // operator will yield 'bslmf::Tag<false>' k_IS_VOID = BSLMF_TAG_TO_INT(( myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...), InvokeResult_VoidChecker())) }; typedef typename InvokeResult_FunctorDeduction<k_IS_VOID, t_FN, t_ARGTYPES...>::type type; // For C++03, the result of invoking // 'myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)' if it can be deduced // without 'decltype'; otherwise 'InvokeResultDeductionFailed'. }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS // ======================================= // struct template InvokeResult_FuncPtrImp // ======================================= #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FuncPtrImp { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-function type, and the 'INVOKE(fn, args...)' expression is // *not* well-formed given 'fn' is an object of the specified 't_FN' type // and 'args...' are objects of the specified 't_ARGTYPES...' types. The // 'INVOKE(fn, args...)' expression in this case is 'fn(args...)'. Note // that this 'struct' does not provide a 'type' typedef. }; template <class t_FN, class... t_ARGTYPES> struct InvokeResult_FuncPtrImp< typename bslmf::VoidType<decltype(InvokeResult_ImpUtils::myDeclval<t_FN>()( InvokeResult_ImpUtils::myDeclval<t_ARGTYPES>()...))>::type, t_FN, t_ARGTYPES...> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-function type, and the 'INVOKE(fn, args...)' expression is // well-formed given 'fn' is an object of the specified 't_FN' type and // 'args...' are objects of the specified 't_ARGTYPES...' types. The // 'INVOKE(fn, args...)' expression in this case is 'fn(args...)'. // TYPES typedef decltype(myDeclval<t_FN>()(myDeclval<t_ARGTYPES>()...)) type; // For C++11 and later, the type of result of the 'INVOKE(fn, args...)' // expression where 'fn' is an object of the specified 't_FN' type, and // 'args...' are objects of the specified 't_ARGTYPES...' types. The // 'INVOKE(fn, args...)' expression in this case is is 'fn(args...)'. }; #else // ! BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, class t_FN, class... t_ARGTYPES> struct InvokeResult_FuncPtrImp { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>. This // specialization is instantiated in C++03 when 't_FN' is a // pointer-to-function type. Note that this C++03 implementation does not // check whether 't_ARGTYPES...' are valid for 't_FN'. typedef typename bslmf::FunctionPointerTraits<t_FN>::ResultType QType; // The return value of the function pointed-to by 't_FN'. typedef typename bsl::conditional< bsl::is_reference<QType>::value || bsl::is_class<QType>::value, QType, typename bsl::remove_cv<QType>::type>::type type; // The return value of the function pointed-to by 't_FN'. If the type // is a scalar rvalue, cv qualifications are stripped off. }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS // ========================================== // struct template InvokeResult_MemFuncPtrImp // ========================================== #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, bool t_ARG1_DERIVES_FROM_CLASS, bool t_ARG1_IS_REFERENCE_WRAPPER, class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImpDispatch; // Forward declaration. // SPECIALIZATIONS template <class t_FN> struct InvokeResult_MemFuncPtrImp<t_FN> { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, and the 't_ARGTYPES...' pack is empty. // Note that this 'struct' does not provide a 'type' typedef. }; template <class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImp<t_FN, t_ARG1TYPE, t_ARGTYPES...> : InvokeResult_MemFuncPtrImpDispatch< void, IsAccessibleBaseOf< typename MemberFunctionPointerTraits<t_FN>::ClassType, typename bsl::remove_reference<t_ARG1TYPE>::type>::value, IsReferenceWrapper<typename bsl::remove_const< typename bsl::remove_reference<t_ARG1TYPE>::type>::type>::value, t_FN, t_ARG1TYPE, t_ARGTYPES...> { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, and the 't_ARGTYPES...' pack contains // 1 type or more. }; #else // ! BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_FN, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImp<t_FN, t_ARGTYPES...> { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>. This // specialization is instantiated in C++03 when 't_FN' is a // pointer-to-member-function type. typedef typename MemberFunctionPointerTraits<t_FN>::ResultType QType; // The return value of the function pointed-to by 't_FN'. typedef typename bsl::conditional< bsl::is_reference<QType>::value || bsl::is_class<QType>::value, QType, typename bsl::remove_cv<QType>::type>::type type; // The return value of the function pointed-to by 't_FN'. If the type // is a scalar rvalue, cv qualifications are stripped off. }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS // ================================================== // struct template InvokeResult_MemFuncPtrImpDispatch // ================================================== #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, bool t_ARG1_DERIVES_FROM_CLASS, bool t_ARG1_IS_REFERENCE_WRAPPER, class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImpDispatch { // Implementation of 'invoke_result<t_FN, t_ARG1TYPE, t_ARGTYPES...>'. // This specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, and the 'INVOKE(fn, arg1, args...)' // expression is *not* well-formed given 'fn' is an object of the specified // 't_FN' type and 'arg1, args...' are objects of the specified // 't_ARG1TYPE, t_ARGTYPES...' types. Note that this 'struct' does not // provide a 'type' typedef. }; template <class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImpDispatch< typename bslmf::VoidType< decltype(((*InvokeResult_ImpUtils::myDeclval<t_ARG1TYPE>()).* InvokeResult_ImpUtils::myDeclval<t_FN>())( InvokeResult_ImpUtils::myDeclval<t_ARGTYPES>()...))>::type, /* t_ARG1_DERIVES_FROM_CLASS */ false, /* t_ARG1_IS_REFERENCE_WRAPPER */ false, t_FN, t_ARG1TYPE, t_ARGTYPES...> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARG1TYPE, t_ARGTYPES...>'. // This specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, 't_ARG1TYPE' is neither a class type // that derives from the class type of 't_FN' nor a specialization of // 'bsl::reference_wrapper', and the 'INVOKE(fn, arg1, args...)' expression // is well-formed given 'fn' is an object of the specified 't_FN' type and // 'arg1, args...' are objects of the specified 't_ARG1TYPE, t_ARGTYPES...' // types. The 'INVOKE(fn, arg1, args...)' expression in this case is // '((*arg1).*fn)(args...)'. // TYPES typedef decltype(((*myDeclval<t_ARG1TYPE>()).* myDeclval<t_FN>())(myDeclval<t_ARGTYPES>()...)) type; // For C++11 and later, the type of the 'INVOKE(fn, args...)' // expression where 'fn' is an object of the specified 't_FN' type, and // 'arg1, args...' are objects of the specified // 't_ARG1TYPE, t_ARGTYPES...' types. The 'INVOKE(fn, arg1, args...)' // expression in this case is '((*arg1).*fn)(args...)'. }; template <class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImpDispatch< typename bslmf::VoidType< decltype((InvokeResult_ImpUtils::myDeclval<t_ARG1TYPE>().* InvokeResult_ImpUtils::myDeclval<t_FN>())( InvokeResult_ImpUtils::myDeclval<t_ARGTYPES>()...))>::type, /* t_ARG1_DERIVES_FROM_CLASS */ true, /* t_ARG1_IS_REFERENCE_WRAPPER */ false, t_FN, t_ARG1TYPE, t_ARGTYPES...> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, 't_ARG1TYPE' is a class type that // derives from the class type of 't_FN', and the // 'INVOKE(fn, arg1, args...)' expression is well-formed given 'fn' is an // object of the specified 't_FN' type and 'arg1, args...' are objects of // the specified 't_ARG1TYPE, t_ARGTYPES...' types. The // 'INVOKE(fn, arg1, args...)' expression in this case is // '(arg1.*fn)(args...)'. // TYPES typedef decltype((myDeclval<t_ARG1TYPE>().* myDeclval<t_FN>())(myDeclval<t_ARGTYPES>()...)) type; // For C++11 and later, the type of the 'INVOKE(fn, arg1, args...)' // expression where 'fn' is an object of the specified 't_FN' type, and // 'arg1, args...' are objects of the specified // 't_ARG1TYPE, t_ARGTYPES...' types. The 'INVOKE(fn, arg1, args...)' // expression in this case is '(arg1.*fn)(args...)'. }; template <class t_FN, class t_ARG1TYPE, class... t_ARGTYPES> struct InvokeResult_MemFuncPtrImpDispatch< typename bslmf::VoidType< decltype((InvokeResult_ImpUtils::myDeclval<t_ARG1TYPE>().get().* InvokeResult_ImpUtils::myDeclval<t_FN>())( InvokeResult_ImpUtils::myDeclval<t_ARGTYPES>()...))>::type, /* t_ARG1_DERIVES_FROM_CLASS */ false, /* t_ARG1_IS_REFERENCE_WRAPPER */ true, t_FN, t_ARG1TYPE, t_ARGTYPES...> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-function type, 't_ARG1TYPE' is a specialization of // 'bsl::reference_wrapper', and the 'INVOKE(fn, arg1, args...)' expression // is well-formed given 'fn' is an object of the specified 't_FN' type and // 'arg1, args...' are objects of the specified 't_ARG1TYPE, t_ARGTYPES...' // types. The 'INVOKE(fn, arg1, args...)' expression in this case is // '(arg1.get().*fn)(args...)'. // TYPES typedef decltype((myDeclval<t_ARG1TYPE>().get().* myDeclval<t_FN>())(myDeclval<t_ARGTYPES>()...)) type; // For C++11 and later, the type of the 'INVOKE(fn, arg1, args...)' // expression where 'fn' is an object of the specified 't_FN' type, and // 'arg1, args...' are objects of the specified // 't_ARG1TYPE, t_ARGTYPES...' types. The 'INVOKE(fn, arg1, args...)' // expression in this case is '(arg1.get().*fn)(args...)'. }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS // ========================================= // struct template InvokeResult_MemObjPtrImp // ========================================= #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, bool t_ARG_DERIVES_FROM_CLASS, bool t_ARG_IS_REFERENCE_WRAPPER, class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImpDispatch; // Forward declaration. // SPECIALIZATIONS template <class t_FN, class... t_ARGTYPES> struct InvokeResult_MemObjPtrImp { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type, and the 't_ARGTYPES...' pack is empty or // contains more than 1 type. Note that this 'struct' does not provide a // 'type' typedef. }; template <class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImp<t_FN, t_ARGTYPE> : InvokeResult_MemObjPtrImpDispatch< void, IsAccessibleBaseOf< typename MemberPointerTraits<t_FN>::ClassType, typename bsl::remove_reference<t_ARGTYPE>::type>::value, IsReferenceWrapper<typename bsl::remove_const< typename bsl::remove_reference<t_ARGTYPE>::type>::type>::value, t_FN, t_ARGTYPE> { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>'. This // specialization is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type and the 't_ARGTYPES...' pack contains // exactly 1 type. }; #else // ! BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_FN, class... t_ARGTYPES> struct InvokeResult_MemObjPtrImp { }; template <class t_CLASS, class t_RET, class t_ARGTYPE> struct InvokeResult_MemObjPtrImp<t_RET t_CLASS::*, t_ARGTYPE> { // Implementation of 'invoke_result<t_FN, t_ARGTYPES...>. This // specialization is instantated in C++03 when 't_FN' is a pointer to data // member and 't_ARGTYPE' is an rvalue type. private: typedef InvokeResult_MemPtrArgQualifiers<t_CLASS, t_ARGTYPE> ArgQualifiers; // Determine the cv qualifications and reference qualifications from // 't_ARGTYPE' that should be applied to 't_RET'. typedef typename InvokeResult_AddCVRef<t_RET, ArgQualifiers::k_IS_CONST, ArgQualifiers::k_IS_VOLATILE, ArgQualifiers::k_IS_LVALUE>::type cvtype; // The type of member pointed to by the pointer-to-member-object, with // cv and reference qualifiers taken from 't_ARGTYPE'. public: #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES typedef typename bsl::conditional< ArgQualifiers::k_IS_LVALUE, cvtype, typename bsl::add_rvalue_reference<cvtype>::type>::type type; // Result type. If rvalue references are supported, data members of // rvalues are always returned as rvalue references in C++11 and later. #else typedef cvtype type; // Rvalue result type. #endif }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS // ================================================= // struct template InvokeResult_MemObjPtrImpDispatch // ================================================= #ifdef BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS template <class t_VOID_TYPE, bool t_ARG_DERIVES_FROM_CLASS, bool t_ARG_IS_REFERENCE_WRAPPER, class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImpDispatch { // Implementation of 'invoke_result<t_FN, t_ARGTYPE>'. This specialization // is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type, and the 'INVOKE(fn, arg)' expression is // *not* well-formed given 'fn' is an object of the specified 't_FN' type // and 'arg' is an object of the specified 't_ARGTYPE'. Note that this // 'struct' does not provide a 'type' typedef. }; template <class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImpDispatch< typename bslmf::VoidType< decltype((*InvokeResult_ImpUtils::myDeclval<t_ARGTYPE>()).* InvokeResult_ImpUtils::myDeclval<t_FN>())>::type, /* t_ARG1_DERIVES_FROM_CLASS */ false, /* t_ARG1_IS_REFERENCE_WRAPPER */ false, t_FN, t_ARGTYPE> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPE>'. This specialization // is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type, 't_ARGTYPE' is neither a class type that // derives from the class type of 't_FN' nor a specialization of // 'bsl::reference_wrapper', and the 'INVOKE(fn, arg)' expression is // well-formed given 'fn' is an object of the specified 't_FN' type and // 'arg' is an object of the specified 't_ARGTYPE' type. The // 'INVOKE(fn, arg)' expression in this case is '(*arg).*fn'. // TYPES typedef decltype((*myDeclval<t_ARGTYPE>()).*myDeclval<t_FN>()) type; // For C++11 and later, the type of the 'INVOKE(fn, arg)' expression where // 'fn' is an object of the specified 't_FN' type, and 'arg' is an object // of the specified 't_ARGTYPE' type. The 'INVOKE(fn, arg)' expression in // this case is '(*arg).*fn'. }; template <class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImpDispatch< typename bslmf::VoidType< decltype(InvokeResult_ImpUtils::myDeclval<t_ARGTYPE>().* InvokeResult_ImpUtils::myDeclval<t_FN>())>::type, /* t_ARG_DERIVES_FROM_CLASS */ true, /* t_ARG_IS_REFERENCE_WRAPPER */ false, t_FN, t_ARGTYPE> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPE>'. This specialization // is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type, 't_ARGTYPE' is a class type that derives // from the class type of 't_FN', and the 'INVOKE(fn, arg)' expression is // well-formed given 'fn' is an object of the specified 't_FN' type and // 'arg' is an object of the specified 't_ARGTYPE' type. The // 'INVOKE(fn, arg)' expression in this case is 'arg1.*fn'. // TYPES typedef decltype(myDeclval<t_ARGTYPE>().*myDeclval<t_FN>()) type; // For C++11 and later, the type of the 'INVOKE(fn, arg)' expression where // 'fn' is an object of the specified 't_FN' type, and 'arg' is an object // of the specified 't_ARGTYPE' type. The 'INVOKE(fn, arg)' expression in // this case is 'arg1.*fn'. }; template <class t_FN, class t_ARGTYPE> struct InvokeResult_MemObjPtrImpDispatch< typename bslmf::VoidType< decltype(InvokeResult_ImpUtils::myDeclval<t_ARGTYPE>().get().* InvokeResult_ImpUtils::myDeclval<t_FN>())>::type, /* t_ARG1_DERIVES_FROM_CLASS */ false, /* t_ARG1_IS_REFERENCE_WRAPPER */ true, t_FN, t_ARGTYPE> : InvokeResult_ImpUtils { // Implementation of 'invoke_result<t_FN, t_ARGTYPE>'. This specialization // is instantiated in C++11 and later when 't_FN' is a // pointer-to-member-object type, 't_ARGTYPE' is a specialization of // 'bsl::reference_wrapper', and the 'INVOKE(fn, arg)' expression is // well-formed given 'fn' is an object of the specified 't_FN' type and // 'arg' is an object of the specified 't_ARGTYPE' type. The // 'INVOKE(fn, arg)' expression in this case is 'arg.get().*fn'. // TYPES typedef decltype(myDeclval<t_ARGTYPE>().get().*myDeclval<t_FN>()) type; // For C++11 and later, the type of the 'INVOKE(fn, arg)' expression where // 'fn' is an object of the specified 't_FN' type, and 'arg' is an object // of the specified 't_ARGTYPE' type. The 'INVOKE(fn, arg)' expression in // this case is 'arg.get().*fn'. }; #endif // BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS #endif } // close package namespace } // close enterprise namespace #endif // End C++11 code #endif // ! defined(INCLUDED_BSLMF_INVOKERESULT) // ---------------------------------------------------------------------------- // Copyright 2018 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 ----------------------------------