Index: libcxx/trunk/include/type_traits =================================================================== --- libcxx/trunk/include/type_traits +++ libcxx/trunk/include/type_traits @@ -137,13 +137,11 @@ template struct is_base_of; template struct is_convertible; - template struct is_callable; // not defined - template - struct is_callable; - - template struct is_nothrow_callable; // not defined - template - struct is_nothrow_callable; + template struct is_invocable; + template struct is_invocable_r; + + template struct is_nothrow_invocable; + template struct is_nothrow_invocable_r; // Alignment properties and transformations: template struct alignment_of; @@ -157,6 +155,7 @@ template struct underlying_type; template class result_of; // undefined template class result_of; + template struct invoke_result; // C++17 // const-volatile modifications: template @@ -215,8 +214,10 @@ using common_type_t = typename common_type::type; // C++14 template using underlying_type_t = typename underlying_type::type; // C++14 - template - using result_of_t = typename result_of::type; // C++14 + template + using result_of_t = typename result_of::type; // C++14 + template + using invoke_result_t = typename invoke_result::type; // C++17 template using void_t = void; // C++17 @@ -370,10 +371,14 @@ = is_base_of::value; // C++17 template constexpr bool is_convertible_v = is_convertible::value; // C++17 - template constexpr bool is_callable_v - = is_callable::value; // C++17 - template constexpr bool is_nothrow_callable_v - = is_nothrow_callable::value; // C++17 + template constexpr bool is_invocable_v + = is_invocable::value; // C++17 + template constexpr bool is_invocable_r_v + = is_invocable_r::value; // C++17 + template constexpr bool is_nothrow_invocable_v + = is_nothrow_invocable::value; // C++17 + template constexpr bool is_nothrow_invocable_r_v + = is_nothrow_invocable_r::value; // C++17 // [meta.logical], logical operator traits: template struct conjunction; // C++17 @@ -4402,6 +4407,13 @@ >; template +using __nothrow_invokable = + __nothrow_invokable_r_imp< + __invokable<_Fp, _Args...>::value, + true, void, _Fp, _Args... + >; + +template struct __invoke_of : public enable_if< __invokable<_Fp, _Args...>::value, @@ -4423,30 +4435,48 @@ #if _LIBCPP_STD_VER > 14 -// is_callable +// invoke_result -template -struct _LIBCPP_TEMPLATE_VIS is_callable; +template +struct _LIBCPP_TEMPLATE_VIS invoke_result + : __invoke_of<_Fn, _Args...> +{ +}; + +template +using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; + +// is_invocable -template -struct _LIBCPP_TEMPLATE_VIS is_callable<_Fn(_Args...), _Ret> +template +struct _LIBCPP_TEMPLATE_VIS is_invocable + : integral_constant::value> {}; + +template +struct _LIBCPP_TEMPLATE_VIS is_invocable_r : integral_constant::value> {}; -template -constexpr bool is_callable_v = is_callable<_Fn, _Ret>::value; +template +constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + +template +constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; // is_nothrow_callable -template -struct _LIBCPP_TEMPLATE_VIS is_nothrow_callable; +template +struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable + : integral_constant::value> {}; + +template +struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r + : integral_constant::value> {}; -template -struct _LIBCPP_TEMPLATE_VIS is_nothrow_callable<_Fn(_Args...), _Ret> - : integral_constant::value> -{}; +template +constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value; -template -constexpr bool is_nothrow_callable_v = is_nothrow_callable<_Fn, _Ret>::value; +template +constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; #endif // _LIBCPP_STD_VER > 14 Index: libcxx/trunk/include/variant =================================================================== --- libcxx/trunk/include/variant +++ libcxx/trunk/include/variant @@ -582,7 +582,7 @@ private: template static constexpr void __std_visit_exhaustive_visitor_check() { - static_assert(is_callable_v<_Visitor(_Values...)>, + static_assert(is_invocable_v<_Visitor, _Values...>, "`std::visit` requires the visitor to be exhaustive."); } Index: libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp +++ libcxx/trunk/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp @@ -438,26 +438,26 @@ void call_operator_sfinae_test() { { // wrong number of arguments using T = decltype(std::not_fn(returns_true)); - static_assert(std::is_callable::value, ""); // callable only with no args - static_assert(!std::is_callable::value, ""); + static_assert(std::is_invocable::value, ""); // callable only with no args + static_assert(!std::is_invocable::value, ""); } { // violates const correctness (member function pointer) using T = decltype(std::not_fn(&MemFunCallable::return_value_nc)); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); } { // violates const correctness (call object) using Obj = CopyCallable; using NCT = decltype(std::not_fn(Obj{true})); using CT = const NCT; - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); } { // returns bad type with no operator! auto fn = [](auto x) { return x; }; using T = decltype(std::not_fn(fn)); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); } } Index: libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp +++ libcxx/trunk/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp @@ -32,7 +32,7 @@ static_assert(!std::is_copy_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); #if TEST_STD_VER > 14 - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); #endif } Index: libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_callable.pass.cpp @@ -1,160 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// type_traits - -// is_callable - -// Most testing of is_callable is done within the [meta.trans.other] result_of -// tests. - -#include -#include -#include - -#include "test_macros.h" - -struct Tag {}; -struct DerFromTag : Tag {}; - -struct Implicit { - Implicit(int) {} -}; - -struct Explicit { - explicit Explicit(int) {} -}; - -struct NotCallableWithInt { - int operator()(int) = delete; - int operator()(Tag) { return 42; } -}; - -int main() -{ - { - using Fn = int(Tag::*)(int); - using RFn = int(Tag::*)(int) &&; - // INVOKE bullet 1, 2 and 3 - { - // Bullet 1 - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - { - // Bullet 2 - using T = std::reference_wrapper; - using DT = std::reference_wrapper; - using CT = std::reference_wrapper; - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - { - // Bullet 3 - using T = Tag*; - using DT = DerFromTag*; - using CT = const Tag*; - using ST = std::unique_ptr; - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - } - { - // Bullets 4, 5 and 6 - using Fn = int (Tag::*); - static_assert(!std::is_callable::value, ""); - { - // Bullet 4 - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - } - { - // Bullet 5 - using T = std::reference_wrapper; - using DT = std::reference_wrapper; - using CT = std::reference_wrapper; - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - } - { - // Bullet 6 - using T = Tag*; - using DT = DerFromTag*; - using CT = const Tag*; - using ST = std::unique_ptr; - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - } - } - { - // INVOKE bullet 7 - { - // Function pointer - using Fp = void(*)(Tag&, int); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - { - // Function reference - using Fp = void(&)(Tag&, int); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - { - // Function object - using Fn = NotCallableWithInt; - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - } - { - // Check that the conversion to the return type is properly checked - using Fn = int(*)(); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); - static_assert(!std::is_callable::value, ""); - } - { - // Check for is_callable_v - using Fn = void(*)(); - static_assert(std::is_callable_v, ""); - static_assert(!std::is_callable_v, ""); - } -} Index: libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp @@ -0,0 +1,166 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_invocable + +// Most testing of is_invocable is done within the [meta.trans.other] result_of +// tests. + +#include +#include +#include + +#include "test_macros.h" + +struct Tag {}; +struct DerFromTag : Tag {}; + +struct Implicit { + Implicit(int) {} +}; + +struct Explicit { + explicit Explicit(int) {} +}; + +struct NotCallableWithInt { + int operator()(int) = delete; + int operator()(Tag) { return 42; } +}; + +int main() +{ + { + using Fn = int(Tag::*)(int); + using RFn = int(Tag::*)(int) &&; + // INVOKE bullet 1, 2 and 3 + { + // Bullet 1 + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + { + // Bullet 2 + using T = std::reference_wrapper; + using DT = std::reference_wrapper; + using CT = std::reference_wrapper; + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + { + // Bullet 3 + using T = Tag*; + using DT = DerFromTag*; + using CT = const Tag*; + using ST = std::unique_ptr; + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + } + { + // Bullets 4, 5 and 6 + using Fn = int (Tag::*); + static_assert(!std::is_invocable::value, ""); + { + // Bullet 4 + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + } + { + // Bullet 5 + using T = std::reference_wrapper; + using DT = std::reference_wrapper; + using CT = std::reference_wrapper; + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + } + { + // Bullet 6 + using T = Tag*; + using DT = DerFromTag*; + using CT = const Tag*; + using ST = std::unique_ptr; + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + } + } + { + // INVOKE bullet 7 + { + // Function pointer + using Fp = void(*)(Tag&, int); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + { + // Function reference + using Fp = void(&)(Tag&, int); + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + { + // Function object + using Fn = NotCallableWithInt; + static_assert(std::is_invocable::value, ""); + static_assert(!std::is_invocable::value, ""); + } + } + { + // Check that the conversion to the return type is properly checked + using Fn = int(*)(); + static_assert(std::is_invocable_r::value, ""); + static_assert(std::is_invocable_r::value, ""); + static_assert(std::is_invocable_r::value, ""); + static_assert(!std::is_invocable_r::value, ""); + } + { + // Check for is_invocable_v + using Fn = void(*)(); + static_assert(std::is_invocable_v, ""); + static_assert(!std::is_invocable_v, ""); + } + { + // Check for is_invocable_r_v + using Fn = void(*)(); + static_assert(std::is_invocable_r_v, ""); + static_assert(!std::is_invocable_r_v, ""); + } +} Index: libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp @@ -1,115 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// type_traits - -// is_nothrow_callable - -#include -#include - -#include "test_macros.h" - -struct Tag {}; - -struct Implicit { - Implicit(int) noexcept {} -}; - -struct ThrowsImplicit { - ThrowsImplicit(int) {} -}; - -struct Explicit { - explicit Explicit(int) noexcept {} -}; - -template -struct CallObject { - Ret operator()(Args&&...) const noexcept(IsNoexcept); -}; - -template -constexpr bool throws_callable() { - return std::is_callable::value && - !std::is_nothrow_callable::value; -} - -template -constexpr bool throws_callable() { - return std::is_callable::value && - !std::is_nothrow_callable::value; -} - -// FIXME(EricWF) Don't test the where noexcept is *not* part of the type system -// once implementations have caught up. -void test_noexcept_function_pointers() -{ - struct Dummy { void foo() noexcept {} static void bar() noexcept {} }; -#if !defined(__cpp_noexcept_function_type) - { - // Check that PMF's and function pointers *work*. is_nothrow_callable will always - // return false because 'noexcept' is not part of the function type. - static_assert(throws_callable(), ""); - static_assert(throws_callable(), ""); - } -#else - { - // Check that PMF's and function pointers actually work and that - // is_nothrow_callable returns true for noexcept PMF's and function - // pointers. - static_assert(std::is_nothrow_callable::value, ""); - static_assert(std::is_nothrow_callable::value, ""); - } -#endif -} - -int main() -{ - { - // Check that the conversion to the return type is properly checked - using Fn = CallObject; - static_assert(std::is_nothrow_callable::value, ""); - static_assert(std::is_nothrow_callable::value, ""); - static_assert(std::is_nothrow_callable::value, ""); - static_assert(throws_callable(), ""); - static_assert(!std::is_nothrow_callable(), ""); - } - { - // Check that the conversion to the parameters is properly checked - using Fn = CallObject; - static_assert(std::is_nothrow_callable::value, ""); - static_assert(std::is_nothrow_callable::value, ""); - static_assert(throws_callable(), ""); - static_assert(!std::is_nothrow_callable::value, ""); - } - { - // Check that the noexcept-ness of function objects is checked. - using Fn = CallObject; - using Fn2 = CallObject; - static_assert(std::is_nothrow_callable::value, ""); - static_assert(throws_callable(), ""); - } - { - // Check that PMD derefs are noexcept - using Fn = int (Tag::*); - static_assert(std::is_nothrow_callable::value, ""); - static_assert(std::is_nothrow_callable::value, ""); - static_assert(throws_callable(), ""); - } - { - // Check for is_nothrow_callable_v - using Fn = CallObject; - static_assert(std::is_nothrow_callable_v, ""); - static_assert(!std::is_nothrow_callable_v, ""); - } - test_noexcept_function_pointers(); -} Index: libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_nothrow_invocable + +#include +#include + +#include "test_macros.h" + +struct Tag {}; + +struct Implicit { + Implicit(int) noexcept {} +}; + +struct ThrowsImplicit { + ThrowsImplicit(int) {} +}; + +struct Explicit { + explicit Explicit(int) noexcept {} +}; + +template +struct CallObject { + Ret operator()(Args&&...) const noexcept(IsNoexcept); +}; + +template +constexpr bool throws_invocable() { + return std::is_invocable::value && + !std::is_nothrow_invocable::value; +} + +template +constexpr bool throws_invocable_r() { + return std::is_invocable_r::value && + !std::is_nothrow_invocable_r::value; +} + +// FIXME(EricWF) Don't test the where noexcept is *not* part of the type system +// once implementations have caught up. +void test_noexcept_function_pointers() +{ + struct Dummy { void foo() noexcept {} static void bar() noexcept {} }; +#if !defined(__cpp_noexcept_function_type) + { + // Check that PMF's and function pointers *work*. is_nothrow_invocable will always + // return false because 'noexcept' is not part of the function type. + static_assert(throws_invocable(), ""); + static_assert(throws_invocable(), ""); + } +#else + { + // Check that PMF's and function pointers actually work and that + // is_nothrow_invocable returns true for noexcept PMF's and function + // pointers. + static_assert(std::is_nothrow_invocable::value, ""); + static_assert(std::is_nothrow_invocable::value, ""); + } +#endif +} + +int main() +{ + { + // Check that the conversion to the return type is properly checked + using Fn = CallObject; + static_assert(std::is_nothrow_invocable_r::value, ""); + static_assert(std::is_nothrow_invocable_r::value, ""); + static_assert(std::is_nothrow_invocable_r::value, ""); + static_assert(throws_invocable_r(), ""); + static_assert(!std::is_nothrow_invocable(), ""); + } + { + // Check that the conversion to the parameters is properly checked + using Fn = CallObject; + static_assert(std::is_nothrow_invocable::value, ""); + static_assert(std::is_nothrow_invocable::value, ""); + static_assert(throws_invocable(), ""); + static_assert(!std::is_nothrow_invocable::value, ""); + } + { + // Check that the noexcept-ness of function objects is checked. + using Fn = CallObject; + using Fn2 = CallObject; + static_assert(std::is_nothrow_invocable::value, ""); + static_assert(throws_invocable(), ""); + } + { + // Check that PMD derefs are noexcept + using Fn = int (Tag::*); + static_assert(std::is_nothrow_invocable::value, ""); + static_assert(std::is_nothrow_invocable_r::value, ""); + static_assert(throws_invocable_r(), ""); + } + { + // Check for is_nothrow_invocable_v + using Fn = CallObject; + static_assert(std::is_nothrow_invocable_v, ""); + static_assert(!std::is_nothrow_invocable_v, ""); + } + { + // Check for is_nothrow_invocable_r_v + using Fn = CallObject; + static_assert(std::is_nothrow_invocable_r_v, ""); + static_assert(!std::is_nothrow_invocable_r_v, ""); + } + test_noexcept_function_pointers(); +} Index: libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp @@ -42,16 +42,46 @@ template struct HasType::type> : std::true_type {}; +#if TEST_STD_VER > 14 +template +struct test_invoke_result; + +template +struct test_invoke_result +{ + static void call() + { + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable_r::value, ""); + static_assert((std::is_same::type, Ret>::value), ""); + } +}; +#endif + template void test_result_of() { + static_assert((std::is_same::type, U>::value), ""); #if TEST_STD_VER > 14 - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); + test_invoke_result::call(); #endif - static_assert((std::is_same::type, U>::value), ""); } +#if TEST_STD_VER > 14 +template +struct test_invoke_no_result; + +template +struct test_invoke_no_result +{ + static void call() + { + static_assert(std::is_invocable::value == false, ""); + static_assert((!HasType >::value), ""); + } +}; +#endif + template void test_no_result() { @@ -59,7 +89,7 @@ static_assert((!HasType >::value), ""); #endif #if TEST_STD_VER > 14 - static_assert(std::is_callable::value == false, ""); + test_invoke_no_result::call(); #endif } Index: libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp +++ libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp @@ -27,6 +27,23 @@ struct F {}; struct FD : public F {}; +#if TEST_STD_VER > 14 +template +struct test_invoke_result; + +template +struct test_invoke_result +{ + static void call() + { + static_assert(std::is_invocable::value, ""); + static_assert(std::is_invocable_r::value, ""); + static_assert((std::is_same::type, Ret>::value), ""); + static_assert((std::is_same, Ret>::value), ""); + } +}; +#endif + template void test_result_of_imp() { @@ -35,8 +52,7 @@ static_assert((std::is_same, U>::value), ""); #endif #if TEST_STD_VER > 14 - static_assert(std::is_callable::value, ""); - static_assert(std::is_callable::value, ""); + test_invoke_result::call(); #endif }