mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-22 16:37:40 +08:00
[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:
@@ -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_) {}
|
||||
|
||||
|
@@ -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'}}
|
||||
}
|
@@ -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>());
|
@@ -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)>);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user