diff --git a/include/etl/function_traits.h b/include/etl/function_traits.h index 5d30d684..48803656 100644 --- a/include/etl/function_traits.h +++ b/include/etl/function_traits.h @@ -21,7 +21,7 @@ copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +FITNESS FOR TArgs PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE @@ -36,101 +36,251 @@ SOFTWARE. #include "type_traits.h" #if ETL_USING_CPP11 + namespace etl { //*************************************************************************** - /// A template to extract the function type traits. + // Primary template (unspecialized) //*************************************************************************** - template + template struct function_traits; //*************************************************************************** - /// Specialisation for function pointers + // Base for plain function type TReturn(TArgs...) //*************************************************************************** template - struct function_traits + struct function_traits { - using function_type = TReturn(TArgs...); ///< The signature of the function. - using return_type = TReturn; ///< The return type. - using object_type = void; ///< The object type, if a member function. - using argument_types = etl::type_list; ///< An etl::type_list containing the function argument types. + public: - static constexpr bool is_function = true; ///< true if the type is a free, static or global function, otherwise false. - static constexpr bool is_member_function = false; ///< true if the type is a member function, otherwise false. - static constexpr bool is_const = false; ///< true if the type is a const member function, otherwise false. - static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes. + using function_type = TReturn(TArgs...); + using return_type = TReturn; + using object_type = void; + using argument_types = etl::type_list; + + static constexpr bool is_function = true; + static constexpr bool is_member_function = false; + static constexpr bool is_functor = false; + static constexpr bool is_const = false; + static constexpr bool is_volatile = false; + static constexpr bool is_noexcept = false; + static constexpr size_t arity = sizeof...(TArgs); + + ETL_DEPRECATED_REASON("Use etl::function_traits::arity instead") + static constexpr size_t argument_count = arity; }; + //*************************************************************************** + // Free function pointer + //*************************************************************************** template - constexpr bool function_traits::is_function; - - template - constexpr bool function_traits::is_member_function; - - template - constexpr bool function_traits::is_const; - - template - constexpr size_t function_traits::argument_count; + struct function_traits : function_traits {}; //*************************************************************************** - /// Specialisation for member function pointers + // Free function reference //*************************************************************************** - template - struct function_traits + template + struct function_traits : function_traits {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + //*************************************************************************** + // Free noexcept function pointer + //*************************************************************************** + template + struct function_traits : function_traits { - using function_type = TReturn(TArgs...); ///< The signature of the function. - using return_type = TReturn; ///< The return type. - using object_type = TObject; ///< The object type, if a member function. - using argument_types = etl::type_list; ///< An etl::type_list containing the function argument types. - - static constexpr bool is_function = false; ///< true if the type is a free, static or global function, otherwise false. - static constexpr bool is_member_function = true; ///< true if the type is a member function, otherwise false. - static constexpr bool is_const = false; ///< true if the type is a const member function, otherwise false. - static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes. + static constexpr bool is_noexcept = true; }; - template - constexpr bool function_traits::is_function; - - template - constexpr bool function_traits::is_member_function; - - template - constexpr bool function_traits::is_const; - - template - constexpr size_t function_traits::argument_count; - //*************************************************************************** - /// Specialisation for const member function pointers + // Free noexcept function reference. //*************************************************************************** - template - struct function_traits + template + struct function_traits : function_traits { - using function_type = TReturn(TArgs...); ///< The signature of the function. - using return_type = TReturn; ///< The return type. - using object_type = TObject; ///< The object type, if a member function. - using argument_types = etl::type_list; ///< An etl::type_list containing the function argument types. + static constexpr bool is_noexcept = true; + }; +#endif - static constexpr bool is_function = false; ///< true if the type is a free, static or global function, otherwise false. - static constexpr bool is_member_function = true; ///< true if the type is a member function, otherwise false. - static constexpr bool is_const = true; ///< true if the type is a const member function, otherwise false. - static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes. + //*************************************************************************** + // Member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + using object_type = TObject; + static constexpr bool is_function = false; + static constexpr bool is_member_function = true; }; + //*************************************************************************** + // Const member function pointers + //*************************************************************************** template - constexpr bool function_traits::is_function; + struct function_traits : function_traits + { + static constexpr bool is_const = true; + }; + + //*************************************************************************** + // Volatile member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_volatile = true; + }; + + //*************************************************************************** + // Const volatile member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_const = true; + static constexpr bool is_volatile = true; + }; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + //*************************************************************************** + // Noexcept member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_noexcept = true; + }; + + //*************************************************************************** + // Const noexcept member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_noexcept = true; + }; + + //*************************************************************************** + // Volatile noexcept member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_noexcept = true; + }; + + //*************************************************************************** + // Const volatile noexcept member function pointers + //*************************************************************************** + template + struct function_traits : function_traits + { + static constexpr bool is_noexcept = true; + }; +#endif + + //*************************************************************************** + // Forward cv/ref on the whole type to the unqualified type. + //*************************************************************************** + template + struct function_traits>::value && + !etl::is_class>::value>> + : function_traits> + { + }; + + //*************************************************************************** + // Functors / lambdas: enable only for class types that have a unique operator() + //*************************************************************************** + namespace private_function_traits + { + //********************************* + // Helper to get pointer to call operator + //********************************* + template + using call_operator_ptr_t = decltype(&U::operator()); + } + + //*************************************************************************** + /// Functors / lambdas specialisation + //*************************************************************************** + template + struct function_traits>::value&& + etl::has_unique_call_operator::value>> + : function_traits> > + { + static constexpr bool is_functor = true; + }; + + //*************************************************************************** + // Out-of-class definitions for the function_traits static members + //*************************************************************************** + // free/function primary template + template + constexpr bool function_traits::is_function; + + template + constexpr bool function_traits::is_member_function; + + template + constexpr bool function_traits::is_functor; + + template + constexpr bool function_traits::is_const; + + template + constexpr bool function_traits::is_volatile; + + template + constexpr bool function_traits::is_noexcept; + + template + constexpr size_t function_traits::arity; + + // member-function-pointer specialization + template + constexpr bool function_traits::is_function; template - constexpr bool function_traits::is_member_function; + constexpr bool function_traits::is_member_function; + + // cv/ref-qualified member-function pointer flags + template + constexpr bool function_traits::is_const; + + template + constexpr bool function_traits::is_volatile; + + template + constexpr bool function_traits::is_const; + + template + constexpr bool function_traits::is_volatile; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template + constexpr bool function_traits::is_noexcept; template - constexpr bool function_traits::is_const; + constexpr bool function_traits::is_noexcept; template - constexpr size_t function_traits::argument_count; + constexpr bool function_traits::is_noexcept; + + template + constexpr bool function_traits::is_noexcept; + + template + constexpr bool function_traits::is_noexcept; +#endif + + //*************************************************************************** + // Functor / lambda specialisation: provide out-of-class definition for is_functor + //*************************************************************************** + template + constexpr bool function_traits>::value && + etl::has_unique_call_operator::value>>::is_functor; } -#endif #endif +#endif \ No newline at end of file diff --git a/include/etl/generators/type_traits_generator.h b/include/etl/generators/type_traits_generator.h index c3a95f22..43096f7b 100644 --- a/include/etl/generators/type_traits_generator.h +++ b/include/etl/generators/type_traits_generator.h @@ -2571,10 +2571,13 @@ typedef integral_constant true_type; // Plain / cv-qualified template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; @@ -2582,18 +2585,41 @@ typedef integral_constant true_type; template struct is_function : etl::true_type {}; - // noexcept variants (if supported by the toolchain) + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + // noexcept variants (if supported) #if ETL_HAS_NOEXCEPT_FUNCTION_TYPE template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + + template struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; #endif #if ETL_USING_CPP17 @@ -2679,26 +2705,74 @@ typedef integral_constant true_type; //*************************************************************************** /// Is T a member function pointer //*************************************************************************** - namespace private_type_traits - { - // Primary: not a member function pointer. - template - struct is_member_function_pointer_helper : etl::false_type - { - }; + template struct is_member_function_pointer : etl::false_type {}; - // If the type is 'TMember TObject::*' then TMember is the member - // Uses etl::is_function to detect member function pointers. - template - struct is_member_function_pointer_helper : etl::is_function - { - }; - } + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; - template - struct is_member_function_pointer : private_type_traits::is_member_function_pointer_helper> - { - }; +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; +#endif #endif #if ETL_USING_CPP17 diff --git a/include/etl/platform.h b/include/etl/platform.h index a4710d09..89fafeef 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -325,6 +325,16 @@ SOFTWARE. #define ETL_HAS_CHRONO_LITERALS_DURATION 1 #endif +//************************************* +// Indicate if noexcept is part of the function type. +#if !defined(ETL_HAS_NOEXCEPT_FUNCTION_TYPE) + #if defined(__cpp_noexcept_function_type) && (__cpp_noexcept_function_type >= 201510) + #define ETL_HAS_NOEXCEPT_FUNCTION_TYPE 1 + #else + #define ETL_HAS_NOEXCEPT_FUNCTION_TYPE 0 + #endif +#endif + //************************************* // The macros below are dependent on the profile. // C++11 @@ -652,6 +662,7 @@ namespace etl static ETL_CONSTANT bool has_chrono_literals_microseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_chrono_literals_nanoseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1); static ETL_CONSTANT bool has_std_byteswap = (ETL_HAS_STD_BYTESWAP == 1); + static ETL_CONSTANT bool has_noexcept_function_type = (ETL_HAS_NOEXCEPT_FUNCTION_TYPE == 1); // Is... static ETL_CONSTANT bool is_debug_build = (ETL_IS_DEBUG_BUILD == 1); diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index bf285583..dbb56fc0 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -2564,10 +2564,13 @@ typedef integral_constant true_type; // Plain / cv-qualified template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; @@ -2575,18 +2578,41 @@ typedef integral_constant true_type; template struct is_function : etl::true_type {}; - // noexcept variants (if supported by the toolchain) + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + // noexcept variants (if supported) #if ETL_HAS_NOEXCEPT_FUNCTION_TYPE template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + template struct is_function : etl::true_type {}; + + template struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; + + template + struct is_function : etl::true_type {}; #endif #if ETL_USING_CPP17 @@ -2672,26 +2698,74 @@ typedef integral_constant true_type; //*************************************************************************** /// Is T a member function pointer //*************************************************************************** - namespace private_type_traits - { - // Primary: not a member function pointer. - template - struct is_member_function_pointer_helper : etl::false_type - { - }; + template struct is_member_function_pointer : etl::false_type {}; - // If the type is 'TMember TObject::*' then TMember is the member - // Uses etl::is_function to detect member function pointers. - template - struct is_member_function_pointer_helper : etl::is_function - { - }; - } + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; - template - struct is_member_function_pointer : private_type_traits::is_member_function_pointer_helper> - { - }; +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; +#endif + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer : etl::true_type {}; + template struct is_member_function_pointer: etl::true_type {}; +#endif #endif #if ETL_USING_CPP17 diff --git a/test/test_function_traits.cpp b/test/test_function_traits.cpp index 3e065f58..56024198 100644 --- a/test/test_function_traits.cpp +++ b/test/test_function_traits.cpp @@ -42,6 +42,13 @@ namespace { } + //***************************************************************************** + // The free noexcept function taking no parameters. + //***************************************************************************** + void free_void_noexcept() noexcept + { + } + //***************************************************************************** // The free function taking an int parameter. //***************************************************************************** @@ -67,6 +74,30 @@ namespace { } + void member_void_noexcept() noexcept + { + } + + void member_void_const_noexcept() const noexcept + { + } + + void member_void_volatile() volatile + { + } + + void member_void_volatile_noexcept() volatile noexcept + { + } + + void member_void_const_volatile() const volatile + { + } + + void member_void_const_volatile_noexcept() const volatile noexcept + { + } + //******************************************* // int int member_int(int i, int j) @@ -86,6 +117,16 @@ namespace (void)j; } }; + + //***************************************************************************** + // A functor with a unique operator() + //***************************************************************************** + struct Functor { int operator()(int x) { return x + 1; } }; + + //***************************************************************************** + // A functor with a unique operator() + //***************************************************************************** + struct FunctorConst { int operator()(int x) const { return x + 1; } }; } namespace @@ -106,8 +147,30 @@ namespace CHECK_TRUE(traits::is_function); CHECK_FALSE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_FALSE(traits::is_const); - CHECK_EQUAL(0, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_free_function_free_void_noexcept) + { + free_void_noexcept(); // Keep clang happy + + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_TRUE(traits::is_function); + CHECK_FALSE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_FALSE(traits::is_const); + CHECK_FALSE(traits::is_volatile); } //************************************************************************* @@ -124,8 +187,11 @@ namespace CHECK_TRUE(traits::is_function); CHECK_FALSE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_FALSE(traits::is_const); - CHECK_EQUAL(2 , traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(2, traits::arity); } //************************************************************************* @@ -140,8 +206,11 @@ namespace CHECK_FALSE(traits::is_function); CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_FALSE(traits::is_const); - CHECK_EQUAL(0, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(0, traits::arity); } //************************************************************************* @@ -156,8 +225,141 @@ namespace CHECK_FALSE(traits::is_function); CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_TRUE(traits::is_const); - CHECK_EQUAL(0, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_noexcept) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_FALSE(traits::is_const); + CHECK_FALSE(traits::is_volatile); +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + CHECK_TRUE(traits::is_noexcept); +#else + CHECK_FALSE(traits::is_noexcept); +#endif + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_const_noexcept) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_TRUE(traits::is_const); + CHECK_FALSE(traits::is_volatile); +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + CHECK_TRUE(traits::is_noexcept); +#else + CHECK_FALSE(traits::is_noexcept); +#endif + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_volatile) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_FALSE(traits::is_const); + CHECK_TRUE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_const_volatile) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_TRUE(traits::is_const); + CHECK_TRUE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_volatile_noexcept) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_FALSE(traits::is_const); + CHECK_TRUE(traits::is_volatile); +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + CHECK_TRUE(traits::is_noexcept); +#else + CHECK_FALSE(traits::is_noexcept); +#endif + CHECK_EQUAL(0, traits::arity); + } + + //************************************************************************* + TEST(test_member_function_void_const_volatile_noexcept) + { + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); + CHECK_TRUE(traits::is_const); + CHECK_TRUE(traits::is_volatile); +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + CHECK_TRUE(traits::is_noexcept); +#else + CHECK_FALSE(traits::is_noexcept); +#endif + CHECK_EQUAL(0, traits::arity); } //************************************************************************* @@ -172,8 +374,11 @@ namespace CHECK_FALSE(traits::is_function); CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_FALSE(traits::is_const); - CHECK_EQUAL(2, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(2, traits::arity); } //************************************************************************* @@ -188,8 +393,11 @@ namespace CHECK_FALSE(traits::is_function); CHECK_TRUE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_TRUE(traits::is_const); - CHECK_EQUAL(2, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(2, traits::arity); } //************************************************************************* @@ -204,8 +412,123 @@ namespace CHECK_TRUE(traits::is_function); CHECK_FALSE(traits::is_member_function); + CHECK_FALSE(traits::is_functor); CHECK_FALSE(traits::is_const); - CHECK_EQUAL(1, traits::argument_count); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(1, traits::arity); + } + + //************************************************************************* + TEST(test_lambda) + { + auto lambda = [](int a, const std::string& s) -> long { return static_cast(a + s.size()); }; + + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_TRUE(traits::is_functor); + CHECK_TRUE(traits::is_const); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(2, traits::arity); + } + + //************************************************************************* + TEST(test_functor) + { + struct functor + { + long operator()(int a, const std::string& s) + { + return static_cast(a + s.size()); + }; + }; + + using traits = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same, traits::argument_types>::value)); + + CHECK_FALSE(traits::is_function); + CHECK_TRUE(traits::is_member_function); + CHECK_TRUE(traits::is_functor); + CHECK_FALSE(traits::is_const); + CHECK_FALSE(traits::is_volatile); + CHECK_FALSE(traits::is_noexcept); + CHECK_EQUAL(2, traits::arity); + } + + //************************************************************************* + // Forwarding of top-level cv/ref on the whole type to the unqualified type + TEST(test_function_traits_forward_cvref_free_ptr) + { + using ptr_t = decltype(&free_void); + using const_ptr_t = typename std::add_const::type; // void(* const)() + using ref_ptr_t = ptr_t&; // void(*&)() + + using traits_c = etl::function_traits; + using traits_r = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE(traits_c::is_function); + CHECK_TRUE(traits_r::is_function); + CHECK_FALSE(traits_c::is_member_function); + CHECK_FALSE(traits_r::is_member_function); + } + + //************************************************************************* + TEST(test_function_traits_forward_cvref_member_ptr) + { + using mptr_t = decltype(&Object::member_int); + using const_mptr_t = typename std::add_const::type; // int (Object::* const)(int,int) + using ref_mptr_t = mptr_t&; // int (Object::*&)(int,int) + + using traits_c = etl::function_traits; + using traits_r = etl::function_traits; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_FALSE(traits_c::is_function); + CHECK_FALSE(traits_r::is_function); + CHECK_TRUE(traits_c::is_member_function); + CHECK_TRUE(traits_r::is_member_function); + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + + //************************************************************************* + // Ensure function_traits resolves for Functor and const Functor + TEST(test_function_traits_functor_and_const_functor) + { + using traits_f = etl::function_traits; + using traits_cf = etl::function_traits; + + // Both should be recognized as functor types + CHECK_TRUE(traits_f::is_functor); + CHECK_TRUE(traits_cf::is_functor); + + // The function_type should be int(int) + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + + // const Functor should be marked const + CHECK_FALSE(traits_f::is_const); + CHECK_TRUE(traits_cf::is_const); + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + CHECK_EQUAL(1, traits_f::arity); + CHECK_EQUAL(1, traits_cf::arity); } }; } diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index f6c8a73f..76d8b8cc 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -140,6 +140,67 @@ namespace struct other_specialized { }; + + struct MF + { + int f(int) { return 0; } + int fc(int) const { return 0; } + int fv(int) volatile { return 0; } + int fcv(int) const volatile { return 0; } + +#if ETL_USING_CPP11 + int fl(int) & { return 0; } + int flc(int) const & { return 0; } + int flv(int) volatile & { return 0; } + int flcv(int) const volatile & { return 0; } + + int fr(int) && { return 0; } + int frc(int) const && { return 0; } + int frv(int) volatile && { return 0; } + int frcv(int) const volatile && { return 0; } +#endif + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + int fn(int) noexcept { return 0; } + int fnc(int) const noexcept { return 0; } + int fnv(int) volatile noexcept { return 0; } + int fncv(int) const volatile noexcept { return 0; } + + int fnl(int) & noexcept { return 0; } + int fnlc(int) const & noexcept { return 0; } + int fnlv(int) volatile & noexcept { return 0; } + int fnlcv(int) const volatile & noexcept { return 0; } + + int fnr(int) && noexcept { return 0; } + int fnrc(int) const && noexcept { return 0; } + int fnrv(int) volatile && noexcept { return 0; } + int fnrcv(int) const volatile && noexcept { return 0; } +#endif + + int fvar(int, ...) { return 0; } + int fvarc(int, ...) const { return 0; } + }; + + struct MO + { + int data; + }; + + static int f(int) { return 0; } + static int fvar(...) { return 0; } + static int fvar2(int, ...) { return 0; } + + template + static T ft(TArgs...) { return T(); } + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + static int fn(int) noexcept { return 0; } + static int fnvar(...) noexcept { return 0; } + static int fnvar2(int, ...) noexcept { return 0; } + + template + static T fnt(TArgs...) noexcept { return T(); } +#endif } // Definitions for when the STL and compiler built-ins are not available. @@ -1490,4 +1551,118 @@ namespace CHECK_FALSE(c1); } #endif + + //************************************************************************* + // Basic cv for member function pointers + TEST(test_is_member_function_pointer) + { + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); +#endif + + CHECK_TRUE((etl::is_member_function_pointer::value)); + CHECK_TRUE((etl::is_member_function_pointer::value)); + } + + //************************************************************************* + // Negative tests for member function pointer trait + TEST(test_is_member_function_pointer_negative) + { + (void)f(0); + + // Free function pointer + CHECK_FALSE((etl::is_member_function_pointer::value)); + + // Member object pointer + CHECK_FALSE((etl::is_member_function_pointer::value)); + + // Plain function type (not pointer) + CHECK_FALSE((etl::is_member_function_pointer::value)); + + // Non-function type + CHECK_FALSE((etl::is_member_function_pointer::value)); + } + + //************************************************************************* + // Member object pointer trait + TEST(test_is_member_object_pointer) + { + CHECK_TRUE((etl::is_member_object_pointer::value)); + + // Not a member object pointer + CHECK_FALSE((etl::is_member_object_pointer::value)); + CHECK_FALSE((etl::is_member_object_pointer::value)); + } + + //************************************************************************* + // Member pointer (either member object or member function pointer) + TEST(test_is_member_pointer_any) + { + CHECK_TRUE((etl::is_member_pointer::value)); + CHECK_TRUE((etl::is_member_pointer::value)); + + // Not member pointers + CHECK_FALSE((etl::is_member_pointer::value)); + CHECK_FALSE((etl::is_member_pointer::value)); + } + + //************************************************************************* + // Function type detection + TEST(test_is_function) + { + (void)f(0); + (void)fvar(); + (void)fvar2(0); + (void)ft(0, 0.0); + + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function)>::value)); + +#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE + (void)fn(0); + (void)fnvar(); + (void)fnvar2(0); + (void)fnt(0, 0.0); + + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function::value)); + CHECK_TRUE((etl::is_function)>::value)); +#endif + + CHECK_FALSE((etl::is_function::value)); + CHECK_FALSE((etl::is_function::value)); + CHECK_FALSE((etl::is_function::value)); + CHECK_FALSE((etl::is_function::value)); // pointer, not function + } }