[libc++] Add C++17 deduction guides for std::function

Summary: http://llvm.org/PR39606

Reviewers: Quuxplusone

Subscribers: christof, dexonsmith, libcxx-commits

Differential Revision: https://reviews.llvm.org/D54410

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@366484 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Louis Dionne
2019-07-18 19:50:56 +00:00
parent 548f2e8e96
commit 56bc01df8f
4 changed files with 337 additions and 0 deletions

View File

@@ -440,6 +440,13 @@ public:
template <typename T> const T* target() const noexcept;
};
// Deduction guides
template<class R, class ...Args>
function(R(*)(Args...)) -> function<R(Args...)>; // since C++17
template<class F>
function(F) -> function<see-below>; // since C++17
// Null pointer comparisons:
template <class R, class ... ArgTypes>
bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
@@ -2335,6 +2342,53 @@ public:
#endif // _LIBCPP_NO_RTTI
};
#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
template<class _Rp, class ..._Ap>
function(_Rp(*)(_Ap...)) -> function<_Rp(_Ap...)>;
template<class _Fp>
struct __strip_signature;
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...)> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) &> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const &> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile &> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile &> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) & noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const & noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile & noexcept> { using type = _Rp(_Ap...); };
template<class _Rp, class _Gp, class ..._Ap>
struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile & noexcept> { using type = _Rp(_Ap...); };
template<class _Fp, class _Stripped = typename __strip_signature<decltype(&_Fp::operator())>::type>
function(_Fp) -> function<_Stripped>;
#endif // !_LIBCPP_HAS_NO_DEDUCTION_GUIDES
template<class _Rp, class ..._ArgTypes>
function<_Rp(_ArgTypes...)>::function(const function& __f) : __f_(__f.__f_) {}

View File

@@ -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.
//
//===----------------------------------------------------------------------===//
// <functional>
// template<class F>
// function(F) -> function<see-below>;
// 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 <functional>
#include <type_traits>
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'}}
}

View File

@@ -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.
//
//===----------------------------------------------------------------------===//
// <functional>
// template<class F>
// function(F) -> function<see-below>;
// UNSUPPORTED: c++98, c++03, c++11, c++14
// UNSUPPORTED: libcpp-no-deduction-guides
#include <functional>
#include <type_traits>
#include <utility>
#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<R()>); \
\
std::function g1 = f1_##N{}; \
ASSERT_SAME_TYPE(decltype(g1), std::function<R(A1)>); \
\
std::function g2 = f2_##N{}; \
ASSERT_SAME_TYPE(decltype(g2), std::function<R(A1, A2)>); \
\
std::function g3 = f3_##N{}; \
ASSERT_SAME_TYPE(decltype(g3), std::function<R(A1, A2, A3)>); \
\
/* explicit */ \
std::function g4{f0_##N{}}; \
ASSERT_SAME_TYPE(decltype(g4), std::function<R()>); \
\
std::function g5{f1_##N{}}; \
ASSERT_SAME_TYPE(decltype(g5), std::function<R(A1)>); \
\
std::function g6{f2_##N{}}; \
ASSERT_SAME_TYPE(decltype(g6), std::function<R(A1, A2)>); \
\
std::function g7{f3_##N{}}; \
ASSERT_SAME_TYPE(decltype(g7), std::function<R(A1, A2, A3)>); \
\
/* from std::function */ \
std::function<R(A1)> unary; \
std::function g8 = unary; \
ASSERT_SAME_TYPE(decltype(g8), std::function<R(A1)>); \
\
std::function g9 = std::move(unary); \
ASSERT_SAME_TYPE(decltype(g9), std::function<R(A1)>); \
\
std::function<R(A1&&)> unary_ref; \
std::function g10 = unary_ref; \
ASSERT_SAME_TYPE(decltype(g10), std::function<R(A1&&)>); \
\
std::function g11 = std::move(unary_ref); \
ASSERT_SAME_TYPE(decltype(g11), std::function<R(A1&&)>); \
} 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 <typename F, typename = decltype(std::function{std::declval<F>()})>
constexpr bool can_deduce() { return true; }
template <typename F>
constexpr bool can_deduce(...) { return false; }
struct invalid1 { };
struct invalid2 {
template <typename ...Args>
void operator()(Args ...);
};
struct invalid3 {
void operator()(int);
void operator()(long);
};
static_assert(!can_deduce<invalid1>());
static_assert(!can_deduce<invalid2>());
static_assert(!can_deduce<invalid3>());

View File

@@ -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.
//
//===----------------------------------------------------------------------===//
// <functional>
// template<class R, class ...Args>
// function(R(*)(Args...)) -> function<R(Args...)>;
// UNSUPPORTED: c++98, c++03, c++11, c++14
// UNSUPPORTED: libcpp-no-deduction-guides
#include <functional>
#include <type_traits>
#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<R()>);
std::function b = &f0;
ASSERT_SAME_TYPE(decltype(b), std::function<R()>);
// explicit
std::function c{f0};
ASSERT_SAME_TYPE(decltype(c), std::function<R()>);
std::function d{&f0};
ASSERT_SAME_TYPE(decltype(d), std::function<R()>);
}
{
// implicit
std::function a = f1;
ASSERT_SAME_TYPE(decltype(a), std::function<R(A1)>);
std::function b = &f1;
ASSERT_SAME_TYPE(decltype(b), std::function<R(A1)>);
// explicit
std::function c{f1};
ASSERT_SAME_TYPE(decltype(c), std::function<R(A1)>);
std::function d{&f1};
ASSERT_SAME_TYPE(decltype(d), std::function<R(A1)>);
}
{
// implicit
std::function a = f2;
ASSERT_SAME_TYPE(decltype(a), std::function<R(A1, A2)>);
std::function b = &f2;
ASSERT_SAME_TYPE(decltype(b), std::function<R(A1, A2)>);
// explicit
std::function c{f2};
ASSERT_SAME_TYPE(decltype(c), std::function<R(A1, A2)>);
std::function d{&f2};
ASSERT_SAME_TYPE(decltype(d), std::function<R(A1, A2)>);
}
{
// implicit
std::function a = f3;
ASSERT_SAME_TYPE(decltype(a), std::function<R(A1, A2, A3)>);
std::function b = &f3;
ASSERT_SAME_TYPE(decltype(b), std::function<R(A1, A2, A3)>);
// explicit
std::function c{f3};
ASSERT_SAME_TYPE(decltype(c), std::function<R(A1, A2, A3)>);
std::function d{&f3};
ASSERT_SAME_TYPE(decltype(d), std::function<R(A1, A2, A3)>);
}
// Make sure defaulted arguments don't mess up the deduction
{
// implicit
std::function a = f4;
ASSERT_SAME_TYPE(decltype(a), std::function<R(A1)>);
std::function b = &f4;
ASSERT_SAME_TYPE(decltype(b), std::function<R(A1)>);
// explicit
std::function c{f4};
ASSERT_SAME_TYPE(decltype(c), std::function<R(A1)>);
std::function d{&f4};
ASSERT_SAME_TYPE(decltype(d), std::function<R(A1)>);
}
}