diff --git a/example/bind_1.cpp b/example/bind_1.cpp index 963fd64..707bc88 100644 --- a/example/bind_1.cpp +++ b/example/bind_1.cpp @@ -8,7 +8,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_BIND -int main(){ return 0; }; +int main(){ return 0; } #else //[ bind_1 diff --git a/example/bind_2.cpp b/example/bind_2.cpp index d02b0e2..6dbb4f6 100644 --- a/example/bind_2.cpp +++ b/example/bind_2.cpp @@ -8,7 +8,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_BIND -int main(){ return 0; }; +int main(){ return 0; } #else //[ bind_2 diff --git a/example/can_invoke_constexpr_function_object.cpp b/example/can_invoke_constexpr_function_object.cpp index 0c1ea8f..43bd5f5 100644 --- a/example/can_invoke_constexpr_function_object.cpp +++ b/example/can_invoke_constexpr_function_object.cpp @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ can_invoke_constexpr_function_object diff --git a/example/can_invoke_constexpr_function_pointer.cpp b/example/can_invoke_constexpr_function_pointer.cpp index 77aaf4c..b192add 100644 --- a/example/can_invoke_constexpr_function_pointer.cpp +++ b/example/can_invoke_constexpr_function_pointer.cpp @@ -7,7 +7,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ can_invoke_constexpr_function_pointer diff --git a/example/can_invoke_constexpr_member_function_pointer.cpp b/example/can_invoke_constexpr_member_function_pointer.cpp index cb4fda3..c823a0f 100644 --- a/example/can_invoke_constexpr_member_function_pointer.cpp +++ b/example/can_invoke_constexpr_member_function_pointer.cpp @@ -7,7 +7,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ can_invoke_constexpr_member_function_pointer diff --git a/example/is_constexpr_function_object.cpp b/example/is_constexpr_function_object.cpp index ca584f8..7a356ab 100644 --- a/example/is_constexpr_function_object.cpp +++ b/example/is_constexpr_function_object.cpp @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ is_constexpr_function_object diff --git a/example/is_constexpr_function_pointer.cpp b/example/is_constexpr_function_pointer.cpp index cf600fd..1d80eb7 100644 --- a/example/is_constexpr_function_pointer.cpp +++ b/example/is_constexpr_function_pointer.cpp @@ -7,7 +7,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ is_constexpr_function_pointer diff --git a/example/make_function.cpp b/example/make_function.cpp index 9c7406a..d2cce77 100644 --- a/example/make_function.cpp +++ b/example/make_function.cpp @@ -6,7 +6,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else //[ make_function diff --git a/include/callable_traits/config.hpp b/include/callable_traits/config.hpp index 1045107..2e2324e 100644 --- a/include/callable_traits/config.hpp +++ b/include/callable_traits/config.hpp @@ -49,6 +49,12 @@ Distributed under the Boost Software License, Version 1.0. #endif //_MSC_VER + +#if defined __GNUC__ && __GNUC__ < 5 +#define CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS +#endif + + #ifndef CALLABLE_TRAITS_ARITY_SEARCH_LIMIT #define CALLABLE_TRAITS_ARITY_SEARCH_LIMIT 10 #endif //CALLABLE_TRAITS_ARITY_SEARCH_LIMIT diff --git a/include/callable_traits/detail/arity.hpp b/include/callable_traits/detail/arity.hpp index 9833c1d..291e2cf 100644 --- a/include/callable_traits/detail/arity.hpp +++ b/include/callable_traits/detail/arity.hpp @@ -132,26 +132,26 @@ namespace callable_traits { ? tentative_max_arity : precient_arity; }; - template + template using arity_t = std::integral_constant::value + arg_tuple_size::value >; - template + template using min_arity_t = std::integral_constant, - arity_t + Traits::is_function_object::value, + function_object_min_arity, + arg_tuple_size >::type::value >; - template + template using max_arity_t = std::integral_constant, - arity_t + Traits::is_function_object::value, + function_object_max_arity, + arg_tuple_size >::type::value >; } diff --git a/include/callable_traits/detail/default_callable_traits.hpp b/include/callable_traits/detail/default_callable_traits.hpp index 533d5a7..c90ef57 100644 --- a/include/callable_traits/detail/default_callable_traits.hpp +++ b/include/callable_traits/detail/default_callable_traits.hpp @@ -39,6 +39,10 @@ namespace callable_traits { // is always std::true_type for classes. using is_function_object = std::false_type; + // std::true_type when it's a function object, AND + // we can't take the address of operator() without casting + using is_overloaded_function_object = std::false_type; + // std::true_type for function references using is_function_reference = std::false_type; diff --git a/include/callable_traits/detail/function_object.hpp b/include/callable_traits/detail/function_object.hpp index 4c7aa47..df3f62f 100644 --- a/include/callable_traits/detail/function_object.hpp +++ b/include/callable_traits/detail/function_object.hpp @@ -38,6 +38,10 @@ namespace callable_traits { using is_function_object = std::integral_constant>::value>; + using is_overloaded_function_object = std::integral_constant>::value>; + using is_member_pointer = std::false_type; using is_member_function_pointer = std::false_type; using remove_member_pointer = type; diff --git a/qtcreator/main/main.cpp b/qtcreator/main/main.cpp index aecc8de..f7b4107 100644 --- a/qtcreator/main/main.cpp +++ b/qtcreator/main/main.cpp @@ -1,68 +1,301 @@ -/*! -Copyright (c) 2016 Barrett Adair +/* +Copyright Barrett Adair 2015 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + */ #include -#include - -#ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; -#else +#include +#include +#include #ifndef CT_ASSERT #define CT_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) #endif //CT_ASSERT -struct foo1 { - int operator()() const { - return 0; - } +struct three_arg_function_object { + void operator()(char&&, float&, int = 0) {} }; -struct foo2 { - constexpr int operator()(int) const { - return 1; - } - constexpr int operator()() const { - return 1; - } +struct three_arg_function_object_with_varargs { + void operator()(volatile char&, const float&, int = 0, ...) {} }; -struct foo3 { - constexpr int bar(int) const { - return 1; - } +struct void_function_object { + void operator()() {} }; -constexpr int bar(const int&) { - return 1; -} +struct vararg_function_object { + void operator()(...) {} +}; -using foo4 = std::integral_constant; +struct void_function_object_default { + void operator()(int = 0) {} +}; -using foo1_pmf = std::integral_constant; -using foo3_pmf = std::integral_constant; +struct vararg_function_object_default { + void operator()(int = 0, ...) {} +}; + +struct template_function_object { + template + void operator()(A&&, B&, C) {} +}; + +struct variadic_template_function_object { + template + void operator()(Args&&...) {} +}; + +struct variadic_template_function_object_plus_one { + template + void operator()(T&&, Args&&...) {} +}; + +struct constrained_variadic_template_function_object { + template + typename std::enable_if::type operator()(Args...) {} +}; + +struct simple_overloaded_function_object { + void operator()(int, int) {} + void operator()(int, int, int, int, int) {} +}; + +struct overloaded_function_object { + void operator()(int) & {} + void operator()(int, int) && {} + void operator()(int, int, int) const & {} + void operator()(int, int, int, int) const && {} + void operator()(int, int, int, int, int) volatile & {} + void operator()(int, int, int, int, int, int) volatile && {} + void operator()(int, int, int, int, int, int, int) const volatile & {} + void operator()(int, int, int, int, int, int, int, int) const volatile && {} +}; + +void three_arg_function(char&&, float&, int = 0) {} +void three_arg_function_with_varargs(char&&, float&, int = 0, ...) {} + +void void_function() {} +void void_function_with_varargs(...) {} namespace ct = callable_traits; +using std::is_same; -CT_ASSERT(!ct::can_invoke_constexpr(foo1{})); -CT_ASSERT(!ct::can_invoke_constexpr(foo1{}, 0)); +template< + typename T, + int ExpectedArity, + int ExpectedMinArity, + int ExpectedMaxArity, + std::size_t SearchLimit +> +void test_arity() { + CT_ASSERT(ct::arity() == ExpectedArity); + CT_ASSERT(ct::min_arity() == ExpectedMinArity); + CT_ASSERT(ct::max_arity() == ExpectedMaxArity); +} -CT_ASSERT( ct::can_invoke_constexpr(foo2{})); -CT_ASSERT( ct::can_invoke_constexpr(foo2{}, 0)); +template< + int ExpectedArity, + int ExpectedMinArity, + int ExpectedMaxArity, + std::size_t SearchLimit, + typename T +> +void test_arity(T&& t) { -CT_ASSERT(!ct::can_invoke_constexpr(foo4{})); -CT_ASSERT( ct::can_invoke_constexpr(foo4{}, 0)); + using arity_result = decltype(ct::arity(t)); + CT_ASSERT(arity_result{} == ExpectedArity); -CT_ASSERT(!ct::can_invoke_constexpr(foo1_pmf{}, foo1{})); -CT_ASSERT(!ct::can_invoke_constexpr(foo1_pmf{}, foo1{}, 0)); + using min_arity_result = decltype(ct::min_arity(t)); + CT_ASSERT(min_arity_result{} == ExpectedMinArity); -CT_ASSERT(!ct::can_invoke_constexpr(foo3_pmf{}, foo3{})); -CT_ASSERT( ct::can_invoke_constexpr(foo3_pmf{}, foo3{}, 0)); + using max_arity_result = decltype(ct::max_arity(t)); + CT_ASSERT(max_arity_result{} == ExpectedMaxArity); +} -int main() {} +constexpr const auto limit = ct::constants::arity_search_limit; +constexpr const auto limit_plus = limit + 1; +constexpr const auto limit_minus = limit - 1; +static_assert(5 <= limit_minus, + "constants::arity_search_limit unexpectedly low for these test cases."); + +namespace ctd = ct::detail; +int main() { + + { + //testing pmf without varargs + using F = three_arg_function_object; + using T = decltype(&F::operator()); + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 3, 3, limit>(&F::operator()); + test_arity<3, 3, 3, limit_plus>(&F::operator()); + test_arity<3, 3, 3, limit_minus>(&F::operator()); + } { + //testing pmf with varargs + using F = three_arg_function_object_with_varargs; + using T = decltype(&F::operator()); + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 3, 3, limit>(&F::operator()); + test_arity<3, 3, 3, limit_plus>(&F::operator()); + test_arity<3, 3, 3, limit_minus>(&F::operator()); + } { + //testing function object without varargs + //min_arity will recognize default argument + using T = three_arg_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 2, 3, limit>(T{}); + test_arity<3, 2, 3, limit_plus>(T{}); + test_arity<3, 2, 3, limit_minus>(T{}); + } { + //testing function object with varargs + //min_arity will recognize default argument + //max_arity will recognize the varargs + using T = three_arg_function_object_with_varargs; + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 2, limit, limit>(T{}); + test_arity<3, 2, limit_plus, limit_plus>(T{}); + test_arity<3, 2, limit_minus, limit_minus>(T{}); + } { + //testing void function object without varargs + using T = void_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<0, 0, 0, limit>(T{}); + test_arity<0, 0, 0, limit_plus>(T{}); + test_arity<0, 0, 0, limit_minus>(T{}); + } { + //testing void function object with varargs + //max_arity will recognize the varargs + using T = vararg_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<0, 0, limit, limit>(T{}); + test_arity<0, 0, limit_plus, limit_plus>(T{}); + test_arity<0, 0, limit_minus, limit_minus>(T{}); + } { + //testing function object with default arg and no varargs + //min arity will recognize the default + using T = void_function_object_default; + test_arity(); + test_arity(); + test_arity(); + test_arity<1, 0, 1, limit>(T{}); + test_arity<1, 0, 1, limit_plus>(T{}); + test_arity<1, 0, 1, limit_minus>(T{}); + } { + //testing function object with default arg and varargs + //min arity will recognize the default + //max_arity will recognize the varargs + using T = vararg_function_object_default; + test_arity(); + test_arity(); + test_arity(); + test_arity<1, 0, limit, limit>(T{}); + test_arity<1, 0, limit_plus, limit_plus>(T{}); + test_arity<1, 0, limit_minus, limit_minus>(T{}); + } { + //testing templated function object + using T = template_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<-1, 3, 3, limit>(T{}); + test_arity<-1, 3, 3, limit_plus>(T{}); + test_arity<-1, 3, 3, limit_minus>(T{}); + } { + //testing templated function object + using T = variadic_template_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<-1, 0, limit, limit>(T{}); + test_arity<-1, 0, limit_plus, limit_plus>(T{}); + test_arity<-1, 0, limit_minus, limit_minus>(T{}); + } { + //testing templated function object (plus one required arg) + using T = variadic_template_function_object_plus_one; + test_arity(); + test_arity(); + test_arity(); + test_arity<-1, 1, limit, limit>(T{}); + test_arity<-1, 1, limit_plus, limit_plus>(T{}); + test_arity<-1, 1, limit_minus, limit_minus>(T{}); + } { + //testing overloaded function object with arity gap + using T = simple_overloaded_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity<-1, 2, 5, limit>(T{}); + test_arity<-1, 2, 5, limit_plus>(T{}); + test_arity<-1, 2, 5, limit_minus>(T{}); + } { + //testing cv/ref qualified overloads + using T = overloaded_function_object; + test_arity(); + test_arity(); + test_arity(); + test_arity(); + test_arity(); + +// MSVC doesn't know what to do with these +#ifndef CALLABLE_TRAITS_MSVC + test_arity(); + test_arity(); + test_arity(); #endif + } + { + //testing function without varargs + using T = decltype(three_arg_function); + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 3, 3, limit>(&three_arg_function); + test_arity<3, 3, 3, limit_plus>(&three_arg_function); + test_arity<3, 3, 3, limit_minus>(&three_arg_function); + } { + //testing function with varargs + using T = decltype(three_arg_function_with_varargs); + test_arity(); + test_arity(); + test_arity(); + test_arity<3, 3, 3, limit>(&three_arg_function_with_varargs); + test_arity<3, 3, 3, limit_plus>(&three_arg_function_with_varargs); + test_arity<3, 3, 3, limit_minus>(&three_arg_function_with_varargs); + } { + //testing void function without varargs + using T = decltype(void_function); + test_arity(); + test_arity(); + test_arity(); + test_arity<0, 0, 0, limit>(&void_function); + test_arity<0, 0, 0, limit_plus>(&void_function); + test_arity<0, 0, 0, limit_minus>(&void_function); + } { + //testing void function with varargs + using T = decltype(void_function_with_varargs); + test_arity(); + test_arity(); + test_arity(); + test_arity<0, 0, 0, limit>(&void_function_with_varargs); + test_arity<0, 0, 0, limit_plus>(&void_function_with_varargs); + test_arity<0, 0, 0, limit_minus>(&void_function_with_varargs); + } + + return 0; +} diff --git a/test/arity.cpp b/test/arity.cpp index 14434fd..9dea65d 100644 --- a/test/arity.cpp +++ b/test/arity.cpp @@ -252,6 +252,7 @@ int main() { test_arity(); test_arity(); +// MSVC doesn't know what to do with these #ifndef CALLABLE_TRAITS_MSVC test_arity(); test_arity(); diff --git a/test/bind_1.cpp b/test/bind_1.cpp index 2188534..c2c66fb 100644 --- a/test/bind_1.cpp +++ b/test/bind_1.cpp @@ -16,8 +16,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_BIND -//feature is unsupported in MSVC -int main(){ return 0; }; +int main(){ return 0; } #else #ifndef CT_ASSERT diff --git a/test/bind_2.cpp b/test/bind_2.cpp index 8a57676..1e7f3d1 100644 --- a/test/bind_2.cpp +++ b/test/bind_2.cpp @@ -16,8 +16,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_BIND -//feature is unsupported in MSVC -int main(){ return 0; }; +int main(){ return 0; } #else #ifndef CT_ASSERT diff --git a/test/can_invoke_constexpr.cpp b/test/can_invoke_constexpr.cpp index 17e34b9..7fbd768 100644 --- a/test/can_invoke_constexpr.cpp +++ b/test/can_invoke_constexpr.cpp @@ -9,7 +9,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else #ifndef CT_ASSERT diff --git a/test/detail/flatten_bind_expressions.cpp b/test/detail/flatten_bind_expressions.cpp index c9b14b8..03259d8 100644 --- a/test/detail/flatten_bind_expressions.cpp +++ b/test/detail/flatten_bind_expressions.cpp @@ -16,7 +16,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_BIND -int main(){ return 0; }; +int main(){ return 0; } #else #ifndef CT_ASSERT diff --git a/test/is_constexpr.cpp b/test/is_constexpr.cpp index 87901d7..bfd7b67 100644 --- a/test/is_constexpr.cpp +++ b/test/is_constexpr.cpp @@ -9,7 +9,7 @@ Distributed under the Boost Software License, Version 1.0. #include #ifdef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS -int main(){ return 0; }; +int main(){ return 0; } #else #ifndef CT_ASSERT