Implement P0358r1. Fixes for not_fn.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@273837 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-06-27 00:40:41 +00:00
parent c297a25c55
commit 715ca51666
2 changed files with 86 additions and 30 deletions

View File

@@ -2618,18 +2618,33 @@ public:
template <class ..._Args> template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
auto operator()(_Args&& ...__args) auto operator()(_Args&& ...__args) &
noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))) noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)))
-> decltype(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)) -> decltype(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))
{ return !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); } { return !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); }
template <class ..._Args> template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
auto operator()(_Args&& ...__args) const auto operator()(_Args&& ...__args) &&
noexcept(noexcept(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...)))
-> decltype(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...))
{ return !_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...); }
template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY
auto operator()(_Args&& ...__args) const&
noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))) noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)))
-> decltype(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)) -> decltype(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))
{ return !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); } { return !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); }
template <class ..._Args>
_LIBCPP_INLINE_VISIBILITY
auto operator()(_Args&& ...__args) const&&
noexcept(noexcept(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...)))
-> decltype(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...))
{ return !_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...); }
private: private:
template <class _RawFunc, template <class _RawFunc,
class = enable_if_t<!is_same<decay_t<_RawFunc>, __not_fn_imp>::value>> class = enable_if_t<!is_same<decay_t<_RawFunc>, __not_fn_imp>::value>>

View File

@@ -88,7 +88,6 @@ struct NoExceptCallable {
Ret value; Ret value;
}; };
struct CopyAssignableWrapper { struct CopyAssignableWrapper {
CopyAssignableWrapper(CopyAssignableWrapper const&) = default; CopyAssignableWrapper(CopyAssignableWrapper const&) = default;
CopyAssignableWrapper(CopyAssignableWrapper&&) = default; CopyAssignableWrapper(CopyAssignableWrapper&&) = default;
@@ -124,32 +123,44 @@ struct MemFunCallable {
bool value; bool value;
}; };
enum CallType { enum CallType : unsigned {
CT_None, CT_None,
CT_Const, CT_NonConst = 1,
CT_NonConst CT_Const = 2,
CT_LValue = 4,
CT_RValue = 8
}; };
inline constexpr CallType operator|(CallType LHS, CallType RHS) {
return static_cast<CallType>(static_cast<unsigned>(LHS) | static_cast<unsigned>(RHS));
}
struct ForwardingCallObject { struct ForwardingCallObject {
template <class ...Args> template <class ...Args>
bool operator()(Args&&... args) & { bool operator()(Args&&... args) & {
set_call<Args&&...>(CT_NonConst); set_call<Args&&...>(CT_NonConst | CT_LValue);
return true; return true;
} }
template <class ...Args> template <class ...Args>
bool operator()(Args&&... args) const & { bool operator()(Args&&... args) const & {
set_call<Args&&...>(CT_Const); set_call<Args&&...>(CT_Const | CT_LValue);
return true; return true;
} }
// Don't allow the call operator to be invoked as an rvalue. // Don't allow the call operator to be invoked as an rvalue.
template <class ...Args> template <class ...Args>
bool operator()(Args&&... args) && = delete; bool operator()(Args&&... args) && {
set_call<Args&&...>(CT_NonConst | CT_RValue);
return true;
}
template <class ...Args> template <class ...Args>
bool operator()(Args&&... args) const && = delete; bool operator()(Args&&... args) const && {
set_call<Args&&...>(CT_Const | CT_RValue);
return true;
}
template <class ...Args> template <class ...Args>
static void set_call(CallType type) { static void set_call(CallType type) {
@@ -450,52 +461,82 @@ void call_operator_forwarding_test()
const auto& c_obj = obj; const auto& c_obj = obj;
{ // test zero args { // test zero args
obj(); obj();
assert(Fn::check_call<>(CT_NonConst)); assert(Fn::check_call<>(CT_NonConst | CT_LValue));
std::move(obj)();
assert(Fn::check_call<>(CT_NonConst | CT_RValue));
c_obj(); c_obj();
assert(Fn::check_call<>(CT_Const)); assert(Fn::check_call<>(CT_Const | CT_LValue));
std::move(c_obj)();
assert(Fn::check_call<>(CT_Const | CT_RValue));
} }
{ // test value categories { // test value categories
int x = 42; int x = 42;
const int cx = 42; const int cx = 42;
obj(x); obj(x);
assert(Fn::check_call<int&>(CT_NonConst)); assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
obj(cx); obj(cx);
assert(Fn::check_call<const int&>(CT_NonConst)); assert(Fn::check_call<const int&>(CT_NonConst | CT_LValue));
obj(std::move(x)); obj(std::move(x));
assert(Fn::check_call<int&&>(CT_NonConst)); assert(Fn::check_call<int&&>(CT_NonConst | CT_LValue));
obj(std::move(cx)); obj(std::move(cx));
assert(Fn::check_call<const int&&>(CT_NonConst)); assert(Fn::check_call<const int&&>(CT_NonConst | CT_LValue));
obj(42); obj(42);
assert(Fn::check_call<int&&>(CT_NonConst)); assert(Fn::check_call<int&&>(CT_NonConst | CT_LValue));
}
{ // test value categories - rvalue
int x = 42;
const int cx = 42;
std::move(obj)(x);
assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
std::move(obj)(cx);
assert(Fn::check_call<const int&>(CT_NonConst | CT_RValue));
std::move(obj)(std::move(x));
assert(Fn::check_call<int&&>(CT_NonConst | CT_RValue));
std::move(obj)(std::move(cx));
assert(Fn::check_call<const int&&>(CT_NonConst | CT_RValue));
std::move(obj)(42);
assert(Fn::check_call<int&&>(CT_NonConst | CT_RValue));
} }
{ // test value categories - const call { // test value categories - const call
int x = 42; int x = 42;
const int cx = 42; const int cx = 42;
c_obj(x); c_obj(x);
assert(Fn::check_call<int&>(CT_Const)); assert(Fn::check_call<int&>(CT_Const | CT_LValue));
c_obj(cx); c_obj(cx);
assert(Fn::check_call<const int&>(CT_Const)); assert(Fn::check_call<const int&>(CT_Const | CT_LValue));
c_obj(std::move(x)); c_obj(std::move(x));
assert(Fn::check_call<int&&>(CT_Const)); assert(Fn::check_call<int&&>(CT_Const | CT_LValue));
c_obj(std::move(cx)); c_obj(std::move(cx));
assert(Fn::check_call<const int&&>(CT_Const)); assert(Fn::check_call<const int&&>(CT_Const | CT_LValue));
c_obj(42); c_obj(42);
assert(Fn::check_call<int&&>(CT_Const)); assert(Fn::check_call<int&&>(CT_Const | CT_LValue));
}
{ // test value categories - const call rvalue
int x = 42;
const int cx = 42;
std::move(c_obj)(x);
assert(Fn::check_call<int&>(CT_Const | CT_RValue));
std::move(c_obj)(cx);
assert(Fn::check_call<const int&>(CT_Const | CT_RValue));
std::move(c_obj)(std::move(x));
assert(Fn::check_call<int&&>(CT_Const | CT_RValue));
std::move(c_obj)(std::move(cx));
assert(Fn::check_call<const int&&>(CT_Const | CT_RValue));
std::move(c_obj)(42);
assert(Fn::check_call<int&&>(CT_Const | CT_RValue));
} }
{ // test multi arg { // test multi arg
int x = 42; int x = 42;
const double y = 3.14; const double y = 3.14;
std::string s = "abc"; std::string s = "abc";
obj(42, std::move(y), s, std::string{"foo"}); obj(42, std::move(y), s, std::string{"foo"});
Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst); Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_LValue);
std::move(obj)(42, std::move(y), s, std::string{"foo"});
Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_RValue);
c_obj(42, std::move(y), s, std::string{"foo"}); c_obj(42, std::move(y), s, std::string{"foo"});
Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const); Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const | CT_LValue);
} std::move(c_obj)(42, std::move(y), s, std::string{"foo"});
{ // call as rvalue test. This should not invoke the functor as an rvalue. Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const | CT_RValue);
std::move(obj)();
assert(Fn::check_call<>(CT_NonConst));
std::move(c_obj)();
assert(Fn::check_call<>(CT_Const));
} }
} }