Index: libcxx/trunk/include/functional =================================================================== --- libcxx/trunk/include/functional +++ libcxx/trunk/include/functional @@ -440,6 +440,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; @@ -2335,6 +2342,53 @@ #endif // _LIBCPP_NO_RTTI }; +#ifndef _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 // !_LIBCPP_HAS_NO_DEDUCTION_GUIDES + template function<_Rp(_ArgTypes...)>::function(const function& __f) : __f_(__f.__f_) {} Index: libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.fail.cpp =================================================================== --- libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.fail.cpp +++ libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-deduction-guides + +// The deduction guides for std::function do not handle rvalue-ref qualified +// call operators and C-style variadics. It also doesn't deduce from nullptr_t. +// Make sure we stick to the specification. + +#include +#include + + +struct R { }; +struct f0 { R operator()() && { return {}; } }; +struct f1 { R operator()(int, ...) { return {}; } }; + +int main() { + std::function f = f0{}; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'function'}} + std::function g = f1{}; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'function'}} + std::function h = nullptr; // expected-error{{no viable constructor or deduction guide for deduction of template arguments of 'function'}} +} Index: libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.pass.cpp +++ libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_F.pass.cpp @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-deduction-guides + +#include +#include +#include + +#include "test_macros.h" + + +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 g0 = f0_##N{}; \ + ASSERT_SAME_TYPE(decltype(g0), std::function); \ + \ + std::function g1 = f1_##N{}; \ + ASSERT_SAME_TYPE(decltype(g1), std::function); \ + \ + std::function g2 = f2_##N{}; \ + ASSERT_SAME_TYPE(decltype(g2), std::function); \ + \ + std::function g3 = f3_##N{}; \ + ASSERT_SAME_TYPE(decltype(g3), std::function); \ + \ + /* explicit */ \ + std::function g4{f0_##N{}}; \ + ASSERT_SAME_TYPE(decltype(g4), std::function); \ + \ + std::function g5{f1_##N{}}; \ + ASSERT_SAME_TYPE(decltype(g5), std::function); \ + \ + std::function g6{f2_##N{}}; \ + ASSERT_SAME_TYPE(decltype(g6), std::function); \ + \ + std::function g7{f3_##N{}}; \ + ASSERT_SAME_TYPE(decltype(g7), std::function); \ + \ + /* from std::function */ \ + std::function unary; \ + std::function g8 = unary; \ + ASSERT_SAME_TYPE(decltype(g8), std::function); \ + \ + std::function g9 = std::move(unary); \ + ASSERT_SAME_TYPE(decltype(g9), std::function); \ + \ + std::function unary_ref; \ + std::function g10 = unary_ref; \ + ASSERT_SAME_TYPE(decltype(g10), std::function); \ + \ + std::function g11 = std::move(unary_ref); \ + ASSERT_SAME_TYPE(decltype(g11), std::function); \ + } 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/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_ptr.pass.cpp =================================================================== --- libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_ptr.pass.cpp +++ libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/deduct_ptr.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-deduction-guides + +#include +#include + +#include "test_macros.h" + + +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 {}; } +R f4(A1 = {}) { return {}; } + +int main() { + { + // implicit + std::function a = f0; + ASSERT_SAME_TYPE(decltype(a), std::function); + + std::function b = &f0; + ASSERT_SAME_TYPE(decltype(b), std::function); + + // explicit + std::function c{f0}; + ASSERT_SAME_TYPE(decltype(c), std::function); + + std::function d{&f0}; + ASSERT_SAME_TYPE(decltype(d), std::function); + } + { + // implicit + std::function a = f1; + ASSERT_SAME_TYPE(decltype(a), std::function); + + std::function b = &f1; + ASSERT_SAME_TYPE(decltype(b), std::function); + + // explicit + std::function c{f1}; + ASSERT_SAME_TYPE(decltype(c), std::function); + + std::function d{&f1}; + ASSERT_SAME_TYPE(decltype(d), std::function); + } + { + // implicit + std::function a = f2; + ASSERT_SAME_TYPE(decltype(a), std::function); + + std::function b = &f2; + ASSERT_SAME_TYPE(decltype(b), std::function); + + // explicit + std::function c{f2}; + ASSERT_SAME_TYPE(decltype(c), std::function); + + std::function d{&f2}; + ASSERT_SAME_TYPE(decltype(d), std::function); + } + { + // implicit + std::function a = f3; + ASSERT_SAME_TYPE(decltype(a), std::function); + + std::function b = &f3; + ASSERT_SAME_TYPE(decltype(b), std::function); + + // explicit + std::function c{f3}; + ASSERT_SAME_TYPE(decltype(c), std::function); + + std::function d{&f3}; + ASSERT_SAME_TYPE(decltype(d), std::function); + } + // Make sure defaulted arguments don't mess up the deduction + { + // implicit + std::function a = f4; + ASSERT_SAME_TYPE(decltype(a), std::function); + + std::function b = &f4; + ASSERT_SAME_TYPE(decltype(b), std::function); + + // explicit + std::function c{f4}; + ASSERT_SAME_TYPE(decltype(c), std::function); + + std::function d{&f4}; + ASSERT_SAME_TYPE(decltype(d), std::function); + } +}