Index: libcxx/include/functional =================================================================== --- libcxx/include/functional +++ libcxx/include/functional @@ -432,6 +432,13 @@ template const T* target() const noexcept; }; +// Deduction guides +template +function(R(*)(Args...)) -> function; // since C++17 + +template +function(F) -> function; // since C++17 + // Null pointer comparisons: template bool operator==(const function&, nullptr_t) noexcept; @@ -1694,6 +1701,53 @@ #endif // _LIBCPP_NO_RTTI }; +#if _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_DEDUCTION_GUIDES) +template +function(_Rp(*)(_Ap...)) -> function<_Rp(_Ap...)>; + +template +struct __strip_signature; + +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...)> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile> { using type = _Rp(_Ap...); }; + +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) &> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const &> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile &> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile &> { using type = _Rp(_Ap...); }; + +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile noexcept> { using type = _Rp(_Ap...); }; + +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) & noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const & noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile & noexcept> { using type = _Rp(_Ap...); }; +template +struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile & noexcept> { using type = _Rp(_Ap...); }; + +template::type> +function(_Fp) -> function<_Stripped>; +#endif // C++17 && has deduction guides + template function<_Rp(_ArgTypes...)>::function(const function& __f) { Index: libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.fail.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template +// function(F) -> function; + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// The deduction guides for std::function do not handle rvalue-ref qualified +// call operators. Make sure we stick to the specification. + +#include +#include + + +struct R { }; +struct f0 { R operator()() && { return {}; } }; + +int main() { + std::function f = f0{}; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'function'}} +} Index: libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template +// function(F) -> function; + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include +#include + + +struct R { }; +struct A1 { }; +struct A2 { }; +struct A3 { }; + +#define DECLARE_FUNCTIONS_WITH_QUALS(N, ...) \ + struct f0_##N { R operator()() __VA_ARGS__ { return {}; } }; \ + struct f1_##N { R operator()(A1) __VA_ARGS__ { return {}; } }; \ + struct f2_##N { R operator()(A1, A2) __VA_ARGS__ { return {}; } }; \ + struct f3_##N { R operator()(A1, A2, A3) __VA_ARGS__ { return {}; } } \ +/**/ + +DECLARE_FUNCTIONS_WITH_QUALS(0, /* nothing */); +DECLARE_FUNCTIONS_WITH_QUALS(1, const); +DECLARE_FUNCTIONS_WITH_QUALS(2, volatile); +DECLARE_FUNCTIONS_WITH_QUALS(3, const volatile); +DECLARE_FUNCTIONS_WITH_QUALS(4, &); +DECLARE_FUNCTIONS_WITH_QUALS(5 , const &); +DECLARE_FUNCTIONS_WITH_QUALS(6 , volatile &); +DECLARE_FUNCTIONS_WITH_QUALS(7 , const volatile &); +DECLARE_FUNCTIONS_WITH_QUALS(8 , noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(9 , const noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(10, volatile noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(11, const volatile noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(12, & noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(13, const & noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(14, volatile & noexcept); +DECLARE_FUNCTIONS_WITH_QUALS(15, const volatile & noexcept); + +int main() { +#define CHECK_FUNCTIONS(N) \ + do { \ + /* implicit */ \ + std::function a = f0_##N{}; \ + static_assert(std::is_same_v>); \ + \ + std::function b = f1_##N{}; \ + static_assert(std::is_same_v>); \ + \ + std::function c = f2_##N{}; \ + static_assert(std::is_same_v>); \ + \ + std::function d = f3_##N{}; \ + static_assert(std::is_same_v>); \ + \ + /* explicit */ \ + std::function e{f0_##N{}}; \ + static_assert(std::is_same_v>); \ + \ + std::function f{f1_##N{}}; \ + static_assert(std::is_same_v>); \ + \ + std::function g{f2_##N{}}; \ + static_assert(std::is_same_v>); \ + \ + std::function h{f3_##N{}}; \ + static_assert(std::is_same_v>); \ + } while (false) \ +/**/ + + // Make sure we can deduce from function objects with valid call operators + CHECK_FUNCTIONS(0); + CHECK_FUNCTIONS(1); + CHECK_FUNCTIONS(2); + CHECK_FUNCTIONS(3); + CHECK_FUNCTIONS(4); + CHECK_FUNCTIONS(5); + CHECK_FUNCTIONS(6); + CHECK_FUNCTIONS(7); + CHECK_FUNCTIONS(8); + CHECK_FUNCTIONS(9); + CHECK_FUNCTIONS(10); + CHECK_FUNCTIONS(11); + CHECK_FUNCTIONS(12); + CHECK_FUNCTIONS(13); + CHECK_FUNCTIONS(14); + CHECK_FUNCTIONS(15); +} + +// Make sure we fail in a SFINAE-friendly manner when we try to deduce +// from a type without a valid call operator. +template ()})> +constexpr bool can_deduce() { return true; } +template +constexpr bool can_deduce(...) { return false; } + +struct invalid1 { }; +struct invalid2 { + template + void operator()(Args ...); +}; +struct invalid3 { + void operator()(int); + void operator()(long); +}; +static_assert(!can_deduce()); +static_assert(!can_deduce()); +static_assert(!can_deduce()); Index: libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_ptr.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_ptr.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template +// function(R(*)(Args...)) -> function; + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + + +struct R { }; +struct A1 { }; +struct A2 { }; +struct A3 { }; + +R f0() { return {}; } +R f1(A1) { return {}; } +R f2(A1, A2) { return {}; } +R f3(A1, A2, A3) { return {}; } + +int main() { + { + // implicit + std::function a = f0; + static_assert(std::is_same_v>); + + std::function b = &f0; + static_assert(std::is_same_v>); + + // explicit + std::function c{f0}; + static_assert(std::is_same_v>); + + std::function d{&f0}; + static_assert(std::is_same_v>); + } + { + // implicit + std::function a = f1; + static_assert(std::is_same_v>); + + std::function b = &f1; + static_assert(std::is_same_v>); + + // explicit + std::function c{f1}; + static_assert(std::is_same_v>); + + std::function d{&f1}; + static_assert(std::is_same_v>); + } + { + // implicit + std::function a = f2; + static_assert(std::is_same_v>); + + std::function b = &f2; + static_assert(std::is_same_v>); + + // explicit + std::function c{f2}; + static_assert(std::is_same_v>); + + std::function d{&f2}; + static_assert(std::is_same_v>); + } + { + // implicit + std::function a = f3; + static_assert(std::is_same_v>); + + std::function b = &f3; + static_assert(std::is_same_v>); + + // explicit + std::function c{f3}; + static_assert(std::is_same_v>); + + std::function d{&f3}; + static_assert(std::is_same_v>); + } +}