diff --git a/example/args/args.cpp b/example/args/args.cpp new file mode 100644 index 0000000..b6d20fc --- /dev/null +++ b/example/args/args.cpp @@ -0,0 +1,58 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 +#include + +namespace ct = callable_traits; + +//all callable types in this example use these parameter types +using expect = std::tuple; + +template +void test(){ + //this example shows how callable_traits::args + //bevaves consistently for many different types + using args = ct::args; + static_assert(std::is_same{}, ""); +} + +int main() { + + + auto lamda = [](int, float&, const char*){}; + using lam = decltype(lamda); + test(); + test(); + test(); + test(); + test(); + + struct foo; + using pmf = void(foo::*)(int, float&, const char*); + test(); + test(); + test(); + test(); + + using function_ptr = void(*)(int, float&, const char*); + test(); + test(); + test(); + test(); + + using function_ref = void(&)(int, float&, const char*); + test(); + + using function = void(int, float&, const char*); + test(); + + using abominable = void(int, float&, const char*) const; + test(); +} + diff --git a/example/bind_2.cpp b/example/bind_expr/example1.cpp similarity index 100% rename from example/bind_2.cpp rename to example/bind_expr/example1.cpp diff --git a/example/bind_1.cpp b/example/bind_expr/example2.cpp similarity index 100% rename from example/bind_1.cpp rename to example/bind_expr/example2.cpp diff --git a/example/can_invoke/function_object.cpp b/example/can_invoke/function_object.cpp index a1a0a97..cf62710 100644 --- a/example/can_invoke/function_object.cpp +++ b/example/can_invoke/function_object.cpp @@ -66,8 +66,8 @@ static_assert(ct::can_invoke(multiply, 1, 2), ""); // <-- success static_assert(!ct::can_invoke(multiply, 1, 2, 3), ""); //static_assert(!ct::can_invoke(multiply, bad, bad), ""); -// The last, commented static_assert would fail compile, because -// the call cannot be SFINAE'd away. Error message in Clang: +// The last, commented static_assert above would fail compile, +// because the call cannot be SFINAE'd away. Error message in Clang: // "invalid operands to binary expression ('Bad' and 'Bad')" int main() {} diff --git a/example/can_invoke/function_pointer.cpp b/example/can_invoke/function_pointer.cpp new file mode 100644 index 0000000..b166f74 --- /dev/null +++ b/example/can_invoke/function_pointer.cpp @@ -0,0 +1,28 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 + +namespace ct = callable_traits; + +int foo(int&& i) { + return i; +} + +// can_invoke returns std::true_type here because the +// arguments are valid to INVOKE +static_assert(ct::can_invoke(&foo, 0), ""); + +int i = 0; + +// can_invoke returns std::false_type here because the +// arguments are NOT valid to INVOKE - foo expects an +// rvalue reference, not an lvalue reference. +static_assert(!ct::can_invoke(&foo, i), ""); + +int main() { return 0; } + diff --git a/example/can_invoke/function_reference.cpp b/example/can_invoke/function_reference.cpp new file mode 100644 index 0000000..dc1315d --- /dev/null +++ b/example/can_invoke/function_reference.cpp @@ -0,0 +1,28 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 + +namespace ct = callable_traits; + +int foo(int&& i) { + return i; +} + +// can_invoke returns std::true_type here because the +// arguments are valid to INVOKE +static_assert(ct::can_invoke(foo, 0), ""); + +int i = 0; + +// can_invoke returns std::false_type here because the +// arguments are NOT valid to INVOKE - foo expects an +// rvalue reference, not an lvalue reference. +static_assert(!ct::can_invoke(foo, i), ""); + +int main() { return 0; } + diff --git a/example/can_invoke/member_function_pointer.cpp b/example/can_invoke/member_function_pointer.cpp index a607092..ca0888d 100644 --- a/example/can_invoke/member_function_pointer.cpp +++ b/example/can_invoke/member_function_pointer.cpp @@ -5,13 +5,8 @@ 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 -// NOTE: Due to non-compliance in MSVC, can_invoke_constexpr -// always returns std::false_type on that compiler, which -// causes a static assert below to fail. - namespace ct = callable_traits; struct foo { @@ -24,9 +19,9 @@ struct foo { // arguments are valid to INVOKE static_assert(ct::can_invoke(&foo::bar, foo{}, 0), ""); - // can_invoke returns std::false_type here because the -// arguments are NOT valid to INVOKE -static_assert(!ct::can_invoke_constexpr(&foo::bar, foo{}), ""); +// arguments are NOT valid to INVOKE - foo::bar can't be +// invoked like a void member function. +static_assert(!ct::can_invoke(&foo::bar, foo{}), ""); int main() { return 0; } diff --git a/example/can_invoke_constexpr/function_object.cpp b/example/can_invoke_constexpr/function_object.cpp index 3fd66fc..0ca2551 100644 --- a/example/can_invoke_constexpr/function_object.cpp +++ b/example/can_invoke_constexpr/function_object.cpp @@ -55,7 +55,8 @@ static_assert(!ct::can_invoke_constexpr(add{}, 3, 7), ""); // return std::false_type when any of the arguments do not decay to literal // types. (see http://en.cppreference.com/w/cpp/concept/LiteralType). // Even though 'S' below is a constexpr function object, it is incompatible -// with can_invoke_constexpr because 'S' isn't literal type. +// with can_invoke_constexpr because 'S' isn't a literal type. Additionally, +// all arguments must be default constructible. struct S { S() = delete; diff --git a/example/can_invoke_constexpr/function_pointer.cpp b/example/can_invoke_constexpr/function_pointer.cpp new file mode 100644 index 0000000..140d864 --- /dev/null +++ b/example/can_invoke_constexpr/function_pointer.cpp @@ -0,0 +1,38 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 + +namespace ct = callable_traits; + +constexpr int seven(int) { + return 7; +} + +using seven_c = std::integral_constant; + +// The first call to can_invoke_constexpr returns std::true_type +// because `seven` is a constexpr function, and valid INVOKE arguments +// are passed. The second call to can_invoke_constexpr returns +// std::false_type, because the arguments are not valid to INVOKE +static_assert(ct::can_invoke_constexpr(seven_c{}, 0), ""); +static_assert(!ct::can_invoke_constexpr(seven_c{}, nullptr), ""); + +int eight(int) { + return 7; +} + +using eight_c = std::integral_constant; + +// `eight` is NOT a constexpr function, so can_invoke_constexpr +// returns `std::false_type` even for valid INVOKE arguments. +static_assert(!ct::can_invoke_constexpr(eight_c{}, 0), ""); +static_assert(!ct::can_invoke_constexpr(eight_c{}, nullptr), ""); + +int main() {} + diff --git a/example/common_signature/common_signature.cpp b/example/common_signature/common_signature.cpp new file mode 100644 index 0000000..b9e536f --- /dev/null +++ b/example/common_signature/common_signature.cpp @@ -0,0 +1,45 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 +#include + +namespace ct = callable_traits; + +struct Vampire {}; +struct Robot {}; +struct Animal {}; +struct Dog : Animal {}; +struct Poodle : Dog {}; +struct Monster : Poodle, Robot, Vampire {}; + +struct foo { + Poodle make_poodle(Vampire&&, Robot, Monster, Dog, Animal) const { + return Poodle{}; + } +}; + +using A = Dog(*)( const Monster&, Vampire, Robot, Dog, Animal); +using B = Dog(*&)( Monster, Vampire, Robot, Animal, Dog, ...); +using C = Animal(&)( Vampire, Monster, Robot, Dog, const Animal&); +using D = Poodle(foo::*)( Vampire, Robot, Monster, Dog, Animal) const; +using E = Monster( Vampire, Robot, Dog, Monster, Monster) const volatile; + +using test = ct::common_signature; + +using expect = Animal( + Monster, + Monster, + Monster, + Monster, + Monster +); + +static_assert(std::is_same{}, ""); + +int main(){} diff --git a/example/intro.cpp b/example/intro.cpp index 981b4e9..741a654 100644 --- a/example/intro.cpp +++ b/example/intro.cpp @@ -104,14 +104,11 @@ int main() { // Here, int is chosen as the expected argument for the bind expression // because it's the best fit for all three placeholder slots. Behind - // the scenes, this is determined by a cartesian product of conversion - // combinations of the known parameter types represented by the reused - // placeholders (yes, this is slow). The type with the highest number of - // successful conversions "wins". int is chosen over int&& because - // non-reference types are preferred in the case of a tie. + // the scenes, this is determined by a cartesian product of parameter + // conversion combinations that are represented by the reused placeholders. static_assert(std::is_same< ct::args, - std::tuple + std::tuple >{}, ""); // callable_traits can facilitate the construction of std::function objects. @@ -177,6 +174,4 @@ int main() { // note: MSVC likely requires __cdecl for a varargs PMF on your // machine, at least if you intend to do anything useful with it. } - - return 0; } diff --git a/example/is_constexpr/function.cpp b/example/is_constexpr/function_pointer.cpp similarity index 100% rename from example/is_constexpr/function.cpp rename to example/is_constexpr/function_pointer.cpp diff --git a/example/signature/signature.cpp b/example/signature/signature.cpp new file mode 100644 index 0000000..104ec9f --- /dev/null +++ b/example/signature/signature.cpp @@ -0,0 +1,55 @@ +/*! +Copyright (c) 2016 Barrett Adair + +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 +#include + +namespace ct = callable_traits; + +using expect = void(int, float&, const char*); + +template +void test(){ + // this example shows how callable_traits::signature + // bevaves consistently for many different types + using args = ct::signature; + static_assert(std::is_same{}, ""); +} + +int main() { + + auto lamda = [](int, float&, const char*){}; + using lam = decltype(lamda); + test(); + test(); + test(); + test(); + test(); + + struct foo; + using pmf = void(foo::*)(int, float&, const char*); + test(); + test(); + test(); + test(); + + using function_ptr = void(*)(int, float&, const char*); + test(); + test(); + test(); + test(); + + using function_ref = void(&)(int, float&, const char*); + test(); + + using function = void(int, float&, const char*); + test(); + + using abominable = void(int, float&, const char*) const; + test(); +} diff --git a/include/callable_traits/detail/arity.hpp b/include/callable_traits/detail/arity.hpp index a78fe03..9e528de 100644 --- a/include/callable_traits/detail/arity.hpp +++ b/include/callable_traits/detail/arity.hpp @@ -60,11 +60,11 @@ namespace callable_traits { template struct min_args> { - using next = std::conditional_t< + using next = typename std::conditional< sizeof...(I)+1 <= Max, std::make_index_sequence, sentinel - >; + >::type; using result_type = disjunction< is_invokable&...>, diff --git a/include/callable_traits/detail/best_match.hpp b/include/callable_traits/detail/best_match.hpp index 0035125..6f3ab04 100644 --- a/include/callable_traits/detail/best_match.hpp +++ b/include/callable_traits/detail/best_match.hpp @@ -39,13 +39,21 @@ namespace callable_traits { template struct can_convert { + using is_non_reference = std::is_same::type>; + + using arg_type = typename std::conditional< + is_non_reference::value, + T&, + T + >::type; + //todo - this should probably use std::is_convertible instead template struct apply { struct bad{}; - template()(std::declval()))> + template()(std::declval()))> static Ret test(U); template @@ -119,13 +127,34 @@ namespace callable_traits { using best_conversion_result = at<0, typename sorted_cartesian_product_of_conversions::type>; - template - using best_match = typename best_conversion_result::key; - template using has_valid_match = std::integral_constant::count == sizeof...(Ts) >; + + template + struct is_invalid : std::is_same::type {}; + + template + using remove_invalid_types = filter; + + template + struct best_match_t { + + using has_valid = has_valid_match; + + static_assert(has_valid::value, "Conversion not found for all parameter types."); + + using result = typename best_conversion_result::key; + + using type = typename std::enable_if< + has_valid::value, + result + >::type; + }; + + template + using best_match = typename best_match_t::type; } } diff --git a/include/callable_traits/detail/common_signature_t.hpp b/include/callable_traits/detail/common_signature_t.hpp index c8cb91c..20c344d 100644 --- a/include/callable_traits/detail/common_signature_t.hpp +++ b/include/callable_traits/detail/common_signature_t.hpp @@ -72,7 +72,13 @@ namespace callable_traits { template struct best_match_cross_section>{ - using type = best_match>...>; + using result = best_match>...>; + + using type = typename std::conditional< + std::is_rvalue_reference::value, + typename std::remove_reference::type, + result + >::type; }; template diff --git a/include/callable_traits/detail/generalized_class.hpp b/include/callable_traits/detail/generalized_class.hpp index 1feeefe..2e86257 100644 --- a/include/callable_traits/detail/generalized_class.hpp +++ b/include/callable_traits/detail/generalized_class.hpp @@ -19,25 +19,37 @@ namespace callable_traits { namespace detail { + template + struct can_make_reference { + + template + static dummy test(typename std::remove_reference::type*); + + template + static void test(...); + + using type = decltype(can_make_reference::test(nullptr)); + static constexpr bool value = std::is_same::value; + }; + template struct is_class_after_dereference { template struct check {}; - template::value>::value, U>::type> - static typename std::enable_if< - std::is_class< - typename std::remove_reference())>::type - >::value, - std::int8_t - >::type test(std::nullptr_t); + template::value, U>::type, + typename Dereferenced = decltype(*std::declval()), + typename C = typename std::remove_reference::type, + typename std::enable_if::value, int>::type = 0> + static std::int8_t test(int); template static std::int16_t test(...); static constexpr const bool value = - sizeof(test(nullptr)) == sizeof(std::int8_t); + sizeof(test(0)) == sizeof(std::int8_t); }; template diff --git a/include/callable_traits/detail/utility.hpp b/include/callable_traits/detail/utility.hpp index f509d52..8eaae4c 100644 --- a/include/callable_traits/detail/utility.hpp +++ b/include/callable_traits/detail/utility.hpp @@ -203,7 +203,6 @@ struct unknown { unknown() = delete; }; using build_function = typename util_detail::build_function_t::type; - namespace util_detail { template diff --git a/qtcreator/main/main.cpp b/qtcreator/main/main.cpp index a607092..b9e536f 100644 --- a/qtcreator/main/main.cpp +++ b/qtcreator/main/main.cpp @@ -6,27 +6,40 @@ Distributed under the Boost Software License, Version 1.0. */ #include +#include #include -// NOTE: Due to non-compliance in MSVC, can_invoke_constexpr -// always returns std::false_type on that compiler, which -// causes a static assert below to fail. - namespace ct = callable_traits; +struct Vampire {}; +struct Robot {}; +struct Animal {}; +struct Dog : Animal {}; +struct Poodle : Dog {}; +struct Monster : Poodle, Robot, Vampire {}; + struct foo { - int bar(int) const { - return 1; + Poodle make_poodle(Vampire&&, Robot, Monster, Dog, Animal) const { + return Poodle{}; } }; -// can_invoke returns std::true_type here because the -// arguments are valid to INVOKE -static_assert(ct::can_invoke(&foo::bar, foo{}, 0), ""); +using A = Dog(*)( const Monster&, Vampire, Robot, Dog, Animal); +using B = Dog(*&)( Monster, Vampire, Robot, Animal, Dog, ...); +using C = Animal(&)( Vampire, Monster, Robot, Dog, const Animal&); +using D = Poodle(foo::*)( Vampire, Robot, Monster, Dog, Animal) const; +using E = Monster( Vampire, Robot, Dog, Monster, Monster) const volatile; +using test = ct::common_signature; -// can_invoke returns std::false_type here because the -// arguments are NOT valid to INVOKE -static_assert(!ct::can_invoke_constexpr(&foo::bar, foo{}), ""); +using expect = Animal( + Monster, + Monster, + Monster, + Monster, + Monster +); -int main() { return 0; } +static_assert(std::is_same{}, ""); + +int main(){} diff --git a/qtcreator/tests_and_examples/tests_and_examples.pro b/qtcreator/tests_and_examples/tests_and_examples.pro index aecf0f5..4687b24 100644 --- a/qtcreator/tests_and_examples/tests_and_examples.pro +++ b/qtcreator/tests_and_examples/tests_and_examples.pro @@ -6,4 +6,7 @@ OTHER_FILES += ../../test/*.cpp \ ../../example/is_constexpr/*.cpp \ ../../example/can_invoke/*.cpp \ ../../example/can_invoke_constexpr/*.cpp \ - + ../../example/bind_expr/*.cpp \ + ../../example/args/*.cpp \ + ../../example/signature/*.cpp \ + ../../example/common_signature/*.cpp \ diff --git a/test/arity.cpp b/test/arity.cpp index 9413ae0..22c9378 100644 --- a/test/arity.cpp +++ b/test/arity.cpp @@ -56,7 +56,7 @@ struct variadic_template_function_object_plus_one { struct constrained_variadic_template_function_object { template - std::enable_if_t operator()(Args...) {} + typename std::enable_if::type operator()(Args...) {} }; struct simple_overloaded_function_object { diff --git a/test/bind_expression_parser.cpp b/test/bind_expression_parser.cpp index ce41cce..c4df1f9 100644 --- a/test/bind_expression_parser.cpp +++ b/test/bind_expression_parser.cpp @@ -74,7 +74,7 @@ apply(F&& f, Tuple&& t) { std::forward(f), std::forward(t), std::make_index_sequence< - std::tuple_size>::value + std::tuple_size::type>::value >{} ); } @@ -162,4 +162,4 @@ void check_expression_flattening() { using expected_exprs = std::tuple; CT_ASSERT(std::is_same{}); -} \ No newline at end of file +}