diff --git a/example/args.cpp b/example/args.cpp index 67aaf77..a7cf2b8 100644 --- a/example/args.cpp +++ b/example/args.cpp @@ -22,6 +22,7 @@ void test(){ // this example shows how callable_traits::args // bevaves consistently for many different types using args = ct::args; + static_assert(std::is_same::value, ""); } int main() { diff --git a/include/callable_traits/can_invoke.hpp b/include/callable_traits/can_invoke.hpp index e055d91..ce78d27 100644 --- a/include/callable_traits/can_invoke.hpp +++ b/include/callable_traits/can_invoke.hpp @@ -23,6 +23,12 @@ namespace callable_traits { ::std::forward(args)... ); } + + template + inline constexpr auto + can_invoke() { + return detail::can_invoke_impl(); + } } #endif diff --git a/include/callable_traits/can_invoke_constexpr.hpp b/include/callable_traits/can_invoke_constexpr.hpp index faebacb..dbd214f 100644 --- a/include/callable_traits/can_invoke_constexpr.hpp +++ b/include/callable_traits/can_invoke_constexpr.hpp @@ -16,13 +16,23 @@ Distributed under the Boost Software License, Version 1.0. namespace callable_traits { - template + template inline constexpr auto - can_invoke_constexpr(Args&&... args) { + can_invoke_constexpr(T&& t, Args&&... args) { return detail::can_invoke_constexpr_impl( + ::std::forward(t), ::std::forward(args)... ); } + + template + inline constexpr auto + can_invoke_constexpr() { + return typename detail::can_invoke_constexpr_impl_types< + detail::are_all_constexpr_constructible::value, + Args... + >::type{}; + } } #endif diff --git a/include/callable_traits/detail/can_invoke_constexpr_impl.hpp b/include/callable_traits/detail/can_invoke_constexpr_impl.hpp index 3ce07f3..0af88f3 100644 --- a/include/callable_traits/detail/can_invoke_constexpr_impl.hpp +++ b/include/callable_traits/detail/can_invoke_constexpr_impl.hpp @@ -20,6 +20,12 @@ namespace callable_traits { return std::false_type{}; } + template + inline constexpr auto + can_invoke_constexpr_impl_types() { + return std::false_type{}; + } + #else template @@ -39,7 +45,7 @@ namespace callable_traits { //generalize_if_dissimilar is used to abstract away the rules of INVOKE. typename Obj = generalize_if_dissimilar> auto operator()(P&& p, U&& u, Rgs&&... rgs) const -> if_integral_constant, CALLABLE_TRAITS_MAKE_CONSTEXPR(U&&) // resolves to a matching reference to a constexpr K object. Hence, K must be @@ -53,7 +59,7 @@ namespace callable_traits { ((CALLABLE_TRAITS_MAKE_CONSTEXPR(Obj).*std::remove_reference

::type::value)( CALLABLE_TRAITS_MAKE_CONSTEXPR(Rgs&&)... - ), 0)>>; + ), true)>>; auto operator()(...) const -> substitution_failure; }; @@ -69,21 +75,16 @@ namespace callable_traits { //see comments on specialization above template auto operator()(T&& t, Rgs&&...) const -> if_not_integral_constant>; + std::integral_constant>; template::type> auto operator()(T&& t, Rgs&&...) const -> if_integral_constant>; + std::integral_constant>; auto operator()(...) const -> substitution_failure; }; - template - using are_all_constexpr_constructible = CALLABLE_TRAITS_CONJUNCTION( - is_constexpr_constructible... - ); - template>::value, int>::type = 0> inline constexpr auto @@ -98,11 +99,27 @@ namespace callable_traits { using traits = traits; using test = test_invoke_constexpr; using result = decltype(test{}(::std::forward(t), ::std::forward(args)...)); - using failure = substitution_failure; - using is_invalid_invoke = std::is_same; + using is_invalid_invoke = std::is_same; return std::integral_constant{}; } + template + struct can_invoke_constexpr_impl_types { + using type = std::false_type; + }; + + template + struct can_invoke_constexpr_impl_types { + + using traits = traits; + using test = test_invoke_constexpr; + using result = decltype(test{}( ::std::declval(), ::std::declval()...)); + using is_invalid_invoke = std::is_same; + using type = std::integral_constant; + }; + + + #endif //ifndef CALLABLE_TRAITS_DISABLE_CONSTEXPR_CHECKS } } diff --git a/include/callable_traits/detail/can_invoke_impl.hpp b/include/callable_traits/detail/can_invoke_impl.hpp index 8a37f76..18a1f2c 100644 --- a/include/callable_traits/detail/can_invoke_impl.hpp +++ b/include/callable_traits/detail/can_invoke_impl.hpp @@ -21,6 +21,16 @@ namespace callable_traits { return std::integral_constant{}; } + template + inline constexpr auto + can_invoke_impl() { + using traits = detail::traits; + using test = detail::test_invoke; + using result = decltype(test{}(::std::declval(), ::std::declval()...)); + using failure = detail::substitution_failure; + using is_invalid_invoke = std::is_same; + return std::integral_constant{}; + } } } diff --git a/include/callable_traits/detail/utility.hpp b/include/callable_traits/detail/utility.hpp index acbdf56..59e5e2c 100644 --- a/include/callable_traits/detail/utility.hpp +++ b/include/callable_traits/detail/utility.hpp @@ -31,7 +31,7 @@ namespace callable_traits { struct dummy {}; // used as return type in failed SFINAE tests - struct substitution_failure{}; + struct substitution_failure : std::false_type{}; // shorthand for std::tuple_element @@ -308,6 +308,11 @@ namespace callable_traits { struct prepend > { using type = private_tuple; };*/ + + template + using are_all_constexpr_constructible = CALLABLE_TRAITS_CONJUNCTION( + is_constexpr_constructible... + ); } } diff --git a/test/can_invoke.cpp b/test/can_invoke.cpp index eadae80..b86d4ad 100644 --- a/test/can_invoke.cpp +++ b/test/can_invoke.cpp @@ -52,6 +52,12 @@ int main() { CT_ASSERT(!decltype(ct::can_invoke(&foo1::bar, std::declval>(), 'a', 3.0, 1)){}); CT_ASSERT(decltype(ct::can_invoke(&foo1::bar, std::ref(foo), 'a', f, 1)){}); CT_ASSERT(!decltype(ct::can_invoke(&foo1::bar, std::ref(foo), 'a', 3.0, 1)){}); + + //todo - more of these type-level tests + CT_ASSERT(decltype(ct::can_invoke()){}); + CT_ASSERT(!decltype(ct::can_invoke()){}); + CT_ASSERT(decltype(ct::can_invoke()){}); + CT_ASSERT(!decltype(ct::can_invoke()){}); } { float f = 3.0; foo2 foo{}; diff --git a/test/can_invoke_constexpr.cpp b/test/can_invoke_constexpr.cpp index 7fbd768..bb872ef 100644 --- a/test/can_invoke_constexpr.cpp +++ b/test/can_invoke_constexpr.cpp @@ -48,6 +48,7 @@ using foo3_pmf = std::integral_constant; namespace ct = callable_traits; +// value syntax CT_ASSERT(!ct::can_invoke_constexpr(foo1{})); CT_ASSERT(!ct::can_invoke_constexpr(foo1{}, 0)); @@ -63,6 +64,24 @@ CT_ASSERT(!ct::can_invoke_constexpr(foo1_pmf{}, foo1{}, 0)); CT_ASSERT(!ct::can_invoke_constexpr(foo3_pmf{}, foo3{})); CT_ASSERT( ct::can_invoke_constexpr(foo3_pmf{}, foo3{}, 0)); + + +// type syntax +CT_ASSERT(!ct::can_invoke_constexpr()); +CT_ASSERT(!ct::can_invoke_constexpr()); + +CT_ASSERT( ct::can_invoke_constexpr()); +CT_ASSERT( ct::can_invoke_constexpr()); + +CT_ASSERT(!ct::can_invoke_constexpr()); +CT_ASSERT( ct::can_invoke_constexpr()); + +CT_ASSERT(!ct::can_invoke_constexpr()); +CT_ASSERT(!ct::can_invoke_constexpr()); + +CT_ASSERT(!ct::can_invoke_constexpr()); +CT_ASSERT( ct::can_invoke_constexpr()); + int main() {} #endif