forked from OSchip/llvm-project
Add C++17 std::not_fn negator.
Summary: Exactly what it sounds like. I plan to commit this in a couple of days assuming no objections. Reviewers: mclow.lists, EricWF Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D20799 llvm-svn: 271464
This commit is contained in:
parent
5a7159c416
commit
5725756791
|
@ -207,6 +207,8 @@ public:
|
|||
|
||||
template <class Predicate> binary_negate<Predicate> not2(const Predicate& pred);
|
||||
|
||||
template <class F> unspecified not_fn(F&& f); // C++17
|
||||
|
||||
template<class T> struct is_bind_expression;
|
||||
template<class T> struct is_placeholder;
|
||||
|
||||
|
@ -2585,11 +2587,54 @@ struct _LIBCPP_TYPE_VIS_ONLY hash
|
|||
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
template <class _Fn, class ..._Args>
|
||||
result_of_t<_Fn&&(_Args&&...)>
|
||||
invoke(_Fn&& __f, _Args&&... __args) {
|
||||
return __invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...);
|
||||
invoke(_Fn&& __f, _Args&&... __args)
|
||||
noexcept(noexcept(_VSTD::__invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...)))
|
||||
{
|
||||
return _VSTD::__invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
template <class _DecayFunc>
|
||||
class _LIBCPP_TYPE_VIS_ONLY __not_fn_imp {
|
||||
_DecayFunc __fd;
|
||||
|
||||
public:
|
||||
__not_fn_imp() = delete;
|
||||
|
||||
template <class ..._Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
auto operator()(_Args&& ...__args)
|
||||
noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)))
|
||||
-> decltype(!_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(__fd, _VSTD::forward<_Args>(__args)...)))
|
||||
-> decltype(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))
|
||||
{ return !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); }
|
||||
|
||||
private:
|
||||
template <class _RawFunc,
|
||||
class = enable_if_t<!is_same<decay_t<_RawFunc>, __not_fn_imp>::value>>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit __not_fn_imp(_RawFunc&& __rf)
|
||||
: __fd(_VSTD::forward<_RawFunc>(__rf)) {}
|
||||
|
||||
template <class _RawFunc>
|
||||
friend inline _LIBCPP_INLINE_VISIBILITY
|
||||
__not_fn_imp<decay_t<_RawFunc>> not_fn(_RawFunc&&);
|
||||
};
|
||||
|
||||
template <class _RawFunc>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
__not_fn_imp<decay_t<_RawFunc>> not_fn(_RawFunc&& __fn) {
|
||||
return __not_fn_imp<decay_t<_RawFunc>>(_VSTD::forward<_RawFunc>(__fn));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// struct hash<T*> in <memory>
|
||||
|
|
|
@ -304,8 +304,46 @@ void bullet_five_tests() {
|
|||
}
|
||||
}
|
||||
|
||||
struct CopyThrows {
|
||||
CopyThrows() {}
|
||||
CopyThrows(CopyThrows const&) {}
|
||||
CopyThrows(CopyThrows&&) noexcept {}
|
||||
};
|
||||
|
||||
struct NoThrowCallable {
|
||||
void operator()() noexcept {}
|
||||
void operator()(CopyThrows) noexcept {}
|
||||
};
|
||||
|
||||
struct ThrowsCallable {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
struct MemberObj {
|
||||
int x;
|
||||
};
|
||||
|
||||
void noexcept_test() {
|
||||
{
|
||||
NoThrowCallable obj;
|
||||
CopyThrows arg;
|
||||
static_assert(noexcept(std::invoke(obj)));
|
||||
static_assert(!noexcept(std::invoke(obj, arg)));
|
||||
static_assert(noexcept(std::invoke(obj, std::move(arg))));
|
||||
}
|
||||
{
|
||||
ThrowsCallable obj;
|
||||
static_assert(!noexcept(std::invoke(obj)));
|
||||
}
|
||||
{
|
||||
MemberObj obj{42};
|
||||
static_assert(noexcept(std::invoke(&MemberObj::x, obj)));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
bullet_one_two_tests();
|
||||
bullet_three_four_tests();
|
||||
bullet_five_tests();
|
||||
noexcept_test();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,540 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
||||
|
||||
// template <class F> unspecified not_fn(F&& f);
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "type_id.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CALLABLE TEST TYPES
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool returns_true() { return true; }
|
||||
|
||||
template <class Ret = bool>
|
||||
struct MoveOnlyCallable {
|
||||
MoveOnlyCallable(MoveOnlyCallable const&) = delete;
|
||||
MoveOnlyCallable(MoveOnlyCallable&& other)
|
||||
: value(other.value)
|
||||
{ other.value = !other.value; }
|
||||
|
||||
template <class ...Args>
|
||||
Ret operator()(Args&&...) { return Ret{value}; }
|
||||
|
||||
explicit MoveOnlyCallable(bool x) : value(x) {}
|
||||
Ret value;
|
||||
};
|
||||
|
||||
template <class Ret = bool>
|
||||
struct CopyCallable {
|
||||
CopyCallable(CopyCallable const& other)
|
||||
: value(other.value) {}
|
||||
|
||||
CopyCallable(CopyCallable&& other)
|
||||
: value(other.value) { other.value = !other.value; }
|
||||
|
||||
template <class ...Args>
|
||||
Ret operator()(Args&&...) { return Ret{value}; }
|
||||
|
||||
explicit CopyCallable(bool x) : value(x) {}
|
||||
Ret value;
|
||||
};
|
||||
|
||||
|
||||
template <class Ret = bool>
|
||||
struct ConstCallable {
|
||||
ConstCallable(ConstCallable const& other)
|
||||
: value(other.value) {}
|
||||
|
||||
ConstCallable(ConstCallable&& other)
|
||||
: value(other.value) { other.value = !other.value; }
|
||||
|
||||
template <class ...Args>
|
||||
Ret operator()(Args&&...) const { return Ret{value}; }
|
||||
|
||||
explicit ConstCallable(bool x) : value(x) {}
|
||||
Ret value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class Ret = bool>
|
||||
struct NoExceptCallable {
|
||||
NoExceptCallable(NoExceptCallable const& other)
|
||||
: value(other.value) {}
|
||||
|
||||
template <class ...Args>
|
||||
Ret operator()(Args&&...) noexcept { return Ret{value}; }
|
||||
|
||||
template <class ...Args>
|
||||
Ret operator()(Args&&...) const noexcept { return Ret{value}; }
|
||||
|
||||
explicit NoExceptCallable(bool x) : value(x) {}
|
||||
Ret value;
|
||||
};
|
||||
|
||||
|
||||
struct CopyAssignableWrapper {
|
||||
CopyAssignableWrapper(CopyAssignableWrapper const&) = default;
|
||||
CopyAssignableWrapper(CopyAssignableWrapper&&) = default;
|
||||
CopyAssignableWrapper& operator=(CopyAssignableWrapper const&) = default;
|
||||
CopyAssignableWrapper& operator=(CopyAssignableWrapper &&) = default;
|
||||
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&...) { return value; }
|
||||
|
||||
explicit CopyAssignableWrapper(bool x) : value(x) {}
|
||||
bool value;
|
||||
};
|
||||
|
||||
|
||||
struct MoveAssignableWrapper {
|
||||
MoveAssignableWrapper(MoveAssignableWrapper const&) = delete;
|
||||
MoveAssignableWrapper(MoveAssignableWrapper&&) = default;
|
||||
MoveAssignableWrapper& operator=(MoveAssignableWrapper const&) = delete;
|
||||
MoveAssignableWrapper& operator=(MoveAssignableWrapper &&) = default;
|
||||
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&...) { return value; }
|
||||
|
||||
explicit MoveAssignableWrapper(bool x) : value(x) {}
|
||||
bool value;
|
||||
};
|
||||
|
||||
struct MemFunCallable {
|
||||
explicit MemFunCallable(bool x) : value(x) {}
|
||||
|
||||
bool return_value() const { return value; }
|
||||
bool return_value_nc() { return value; }
|
||||
bool value;
|
||||
};
|
||||
|
||||
enum CallType {
|
||||
CT_None,
|
||||
CT_Const,
|
||||
CT_NonConst
|
||||
};
|
||||
|
||||
struct ForwardingCallObject {
|
||||
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&... args) & {
|
||||
set_call<Args&&...>(CT_NonConst);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&... args) const & {
|
||||
set_call<Args&&...>(CT_Const);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't allow the call operator to be invoked as an rvalue.
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&... args) && = delete;
|
||||
|
||||
template <class ...Args>
|
||||
bool operator()(Args&&... args) const && = delete;
|
||||
|
||||
template <class ...Args>
|
||||
static void set_call(CallType type) {
|
||||
assert(last_call_type == CT_None);
|
||||
assert(last_call_args == nullptr);
|
||||
last_call_type = type;
|
||||
last_call_args = &makeArgumentID<Args...>();
|
||||
}
|
||||
|
||||
template <class ...Args>
|
||||
static bool check_call(CallType type) {
|
||||
bool result =
|
||||
last_call_type == type
|
||||
&& last_call_args
|
||||
&& *last_call_args == makeArgumentID<Args...>();
|
||||
last_call_type = CT_None;
|
||||
last_call_args = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
static CallType last_call_type;
|
||||
static TypeID const* last_call_args;
|
||||
};
|
||||
|
||||
CallType ForwardingCallObject::last_call_type = CT_None;
|
||||
TypeID const* ForwardingCallObject::last_call_args = nullptr;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOOL TEST TYPES
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EvilBool {
|
||||
static int bang_called;
|
||||
|
||||
EvilBool(EvilBool const&) = default;
|
||||
EvilBool(EvilBool&&) = default;
|
||||
|
||||
friend EvilBool operator!(EvilBool const& other) {
|
||||
++bang_called;
|
||||
return EvilBool{!other.value};
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct MoveOnlyCallable<EvilBool>;
|
||||
friend struct CopyCallable<EvilBool>;
|
||||
friend struct NoExceptCallable<EvilBool>;
|
||||
|
||||
explicit EvilBool(bool x) : value(x) {}
|
||||
EvilBool& operator=(EvilBool const& other) = default;
|
||||
|
||||
public:
|
||||
bool value;
|
||||
};
|
||||
|
||||
int EvilBool::bang_called = 0;
|
||||
|
||||
struct ExplicitBool {
|
||||
ExplicitBool(ExplicitBool const&) = default;
|
||||
ExplicitBool(ExplicitBool&&) = default;
|
||||
|
||||
explicit operator bool() const { return value; }
|
||||
|
||||
private:
|
||||
friend struct MoveOnlyCallable<ExplicitBool>;
|
||||
friend struct CopyCallable<ExplicitBool>;
|
||||
|
||||
explicit ExplicitBool(bool x) : value(x) {}
|
||||
ExplicitBool& operator=(bool x) {
|
||||
value = x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool value;
|
||||
};
|
||||
|
||||
|
||||
struct NoExceptEvilBool {
|
||||
NoExceptEvilBool(NoExceptEvilBool const&) = default;
|
||||
NoExceptEvilBool(NoExceptEvilBool&&) = default;
|
||||
NoExceptEvilBool& operator=(NoExceptEvilBool const& other) = default;
|
||||
|
||||
explicit NoExceptEvilBool(bool x) : value(x) {}
|
||||
|
||||
friend NoExceptEvilBool operator!(NoExceptEvilBool const& other) noexcept {
|
||||
return NoExceptEvilBool{!other.value};
|
||||
}
|
||||
|
||||
bool value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void constructor_tests()
|
||||
{
|
||||
{
|
||||
using T = MoveOnlyCallable<bool>;
|
||||
T value(true);
|
||||
using RetT = decltype(std::not_fn(std::move(value)));
|
||||
static_assert(std::is_move_constructible<RetT>::value);
|
||||
static_assert(!std::is_copy_constructible<RetT>::value);
|
||||
static_assert(!std::is_move_assignable<RetT>::value);
|
||||
static_assert(!std::is_copy_assignable<RetT>::value);
|
||||
auto ret = std::not_fn(std::move(value));
|
||||
// test it was moved from
|
||||
assert(value.value == false);
|
||||
// test that ret() negates the original value 'true'
|
||||
assert(ret() == false);
|
||||
assert(ret(0, 0.0, "blah") == false);
|
||||
// Move ret and test that it was moved from and that ret2 got the
|
||||
// original value.
|
||||
auto ret2 = std::move(ret);
|
||||
assert(ret() == true);
|
||||
assert(ret2() == false);
|
||||
assert(ret2(42) == false);
|
||||
}
|
||||
{
|
||||
using T = CopyCallable<bool>;
|
||||
T value(false);
|
||||
using RetT = decltype(std::not_fn(value));
|
||||
static_assert(std::is_move_constructible<RetT>::value);
|
||||
static_assert(std::is_copy_constructible<RetT>::value);
|
||||
static_assert(!std::is_move_assignable<RetT>::value);
|
||||
static_assert(!std::is_copy_assignable<RetT>::value);
|
||||
auto ret = std::not_fn(value);
|
||||
// test that value is unchanged (copied not moved)
|
||||
assert(value.value == false);
|
||||
// test 'ret' has the original value
|
||||
assert(ret() == true);
|
||||
assert(ret(42, 100) == true);
|
||||
// move from 'ret' and check that 'ret2' has the original value.
|
||||
auto ret2 = std::move(ret);
|
||||
assert(ret() == false);
|
||||
assert(ret2() == true);
|
||||
assert(ret2("abc") == true);
|
||||
}
|
||||
{
|
||||
using T = CopyAssignableWrapper;
|
||||
T value(true);
|
||||
T value2(false);
|
||||
using RetT = decltype(std::not_fn(value));
|
||||
static_assert(std::is_move_constructible<RetT>::value);
|
||||
static_assert(std::is_copy_constructible<RetT>::value);
|
||||
static_assert(std::is_move_assignable<RetT>::value);
|
||||
static_assert(std::is_copy_assignable<RetT>::value);
|
||||
auto ret = std::not_fn(value);
|
||||
assert(ret() == false);
|
||||
auto ret2 = std::not_fn(value2);
|
||||
assert(ret2() == true);
|
||||
ret = ret2;
|
||||
assert(ret() == true);
|
||||
assert(ret2() == true);
|
||||
}
|
||||
{
|
||||
using T = MoveAssignableWrapper;
|
||||
T value(true);
|
||||
T value2(false);
|
||||
using RetT = decltype(std::not_fn(std::move(value)));
|
||||
static_assert(std::is_move_constructible<RetT>::value);
|
||||
static_assert(!std::is_copy_constructible<RetT>::value);
|
||||
static_assert(std::is_move_assignable<RetT>::value);
|
||||
static_assert(!std::is_copy_assignable<RetT>::value);
|
||||
auto ret = std::not_fn(std::move(value));
|
||||
assert(ret() == false);
|
||||
auto ret2 = std::not_fn(std::move(value2));
|
||||
assert(ret2() == true);
|
||||
ret = std::move(ret2);
|
||||
assert(ret() == true);
|
||||
}
|
||||
}
|
||||
|
||||
void return_type_tests()
|
||||
{
|
||||
using std::is_same;
|
||||
{
|
||||
using T = CopyCallable<bool>;
|
||||
auto ret = std::not_fn(T{false});
|
||||
static_assert(is_same<decltype(ret()), bool>::value);
|
||||
static_assert(is_same<decltype(ret("abc")), bool>::value);
|
||||
assert(ret() == true);
|
||||
}
|
||||
{
|
||||
using T = CopyCallable<ExplicitBool>;
|
||||
auto ret = std::not_fn(T{true});
|
||||
static_assert(is_same<decltype(ret()), bool>::value);
|
||||
static_assert(is_same<decltype(ret(std::string("abc"))), bool>::value);
|
||||
assert(ret() == false);
|
||||
}
|
||||
{
|
||||
using T = CopyCallable<EvilBool>;
|
||||
auto ret = std::not_fn(T{false});
|
||||
static_assert(is_same<decltype(ret()), EvilBool>::value);
|
||||
EvilBool::bang_called = 0;
|
||||
auto value_ret = ret();
|
||||
assert(EvilBool::bang_called == 1);
|
||||
assert(value_ret.value == true);
|
||||
ret();
|
||||
assert(EvilBool::bang_called == 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Other tests only test using objects with call operators. Test various
|
||||
// other callable types here.
|
||||
void other_callable_types_test()
|
||||
{
|
||||
{ // test with function pointer
|
||||
auto ret = std::not_fn(returns_true);
|
||||
assert(ret() == false);
|
||||
}
|
||||
{ // test with lambda
|
||||
auto returns_value = [](bool value) { return value; };
|
||||
auto ret = std::not_fn(returns_value);
|
||||
assert(ret(true) == false);
|
||||
assert(ret(false) == true);
|
||||
}
|
||||
{ // test with pointer to member function
|
||||
MemFunCallable mt(true);
|
||||
const MemFunCallable mf(false);
|
||||
auto ret = std::not_fn(&MemFunCallable::return_value);
|
||||
assert(ret(mt) == false);
|
||||
assert(ret(mf) == true);
|
||||
assert(ret(&mt) == false);
|
||||
assert(ret(&mf) == true);
|
||||
}
|
||||
{ // test with pointer to member function
|
||||
MemFunCallable mt(true);
|
||||
MemFunCallable mf(false);
|
||||
auto ret = std::not_fn(&MemFunCallable::return_value_nc);
|
||||
assert(ret(mt) == false);
|
||||
assert(ret(mf) == true);
|
||||
assert(ret(&mt) == false);
|
||||
assert(ret(&mf) == true);
|
||||
}
|
||||
{ // test with pointer to member data
|
||||
MemFunCallable mt(true);
|
||||
const MemFunCallable mf(false);
|
||||
auto ret = std::not_fn(&MemFunCallable::value);
|
||||
assert(ret(mt) == false);
|
||||
assert(ret(mf) == true);
|
||||
assert(ret(&mt) == false);
|
||||
assert(ret(&mf) == true);
|
||||
}
|
||||
}
|
||||
|
||||
void throws_in_constructor_test()
|
||||
{
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
struct ThrowsOnCopy {
|
||||
ThrowsOnCopy(ThrowsOnCopy const&) {
|
||||
throw 42;
|
||||
}
|
||||
ThrowsOnCopy() = default;
|
||||
bool operator()() const { assert(false); }
|
||||
};
|
||||
{
|
||||
ThrowsOnCopy cp;
|
||||
try {
|
||||
std::not_fn(cp);
|
||||
assert(false);
|
||||
} catch (int const& value) {
|
||||
assert(value == 42);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void call_operator_sfinae_test() {
|
||||
{ // wrong number of arguments
|
||||
using T = decltype(std::not_fn(returns_true));
|
||||
static_assert(std::is_callable<T()>::value); // callable only with no args
|
||||
static_assert(!std::is_callable<T(bool)>::value);
|
||||
}
|
||||
{ // violates const correctness (member function pointer)
|
||||
using T = decltype(std::not_fn(&MemFunCallable::return_value_nc));
|
||||
static_assert(std::is_callable<T(MemFunCallable&)>::value);
|
||||
static_assert(!std::is_callable<T(const MemFunCallable&)>::value);
|
||||
}
|
||||
{ // violates const correctness (call object)
|
||||
using Obj = CopyCallable<bool>;
|
||||
using NCT = decltype(std::not_fn(Obj{true}));
|
||||
using CT = const NCT;
|
||||
static_assert(std::is_callable<NCT()>::value);
|
||||
static_assert(!std::is_callable<CT()>::value);
|
||||
}
|
||||
{ // returns bad type with no operator!
|
||||
auto fn = [](auto x) { return x; };
|
||||
using T = decltype(std::not_fn(fn));
|
||||
static_assert(std::is_callable<T(bool)>::value);
|
||||
static_assert(!std::is_callable<T(std::string)>::value);
|
||||
}
|
||||
}
|
||||
|
||||
void call_operator_forwarding_test()
|
||||
{
|
||||
using Fn = ForwardingCallObject;
|
||||
auto obj = std::not_fn(Fn{});
|
||||
const auto& c_obj = obj;
|
||||
{ // test zero args
|
||||
obj();
|
||||
assert(Fn::check_call<>(CT_NonConst));
|
||||
c_obj();
|
||||
assert(Fn::check_call<>(CT_Const));
|
||||
}
|
||||
{ // test value categories
|
||||
int x = 42;
|
||||
const int cx = 42;
|
||||
obj(x);
|
||||
assert(Fn::check_call<int&>(CT_NonConst));
|
||||
obj(cx);
|
||||
assert(Fn::check_call<const int&>(CT_NonConst));
|
||||
obj(std::move(x));
|
||||
assert(Fn::check_call<int&&>(CT_NonConst));
|
||||
obj(std::move(cx));
|
||||
assert(Fn::check_call<const int&&>(CT_NonConst));
|
||||
obj(42);
|
||||
assert(Fn::check_call<int&&>(CT_NonConst));
|
||||
}
|
||||
{ // test value categories - const call
|
||||
int x = 42;
|
||||
const int cx = 42;
|
||||
c_obj(x);
|
||||
assert(Fn::check_call<int&>(CT_Const));
|
||||
c_obj(cx);
|
||||
assert(Fn::check_call<const int&>(CT_Const));
|
||||
c_obj(std::move(x));
|
||||
assert(Fn::check_call<int&&>(CT_Const));
|
||||
c_obj(std::move(cx));
|
||||
assert(Fn::check_call<const int&&>(CT_Const));
|
||||
c_obj(42);
|
||||
assert(Fn::check_call<int&&>(CT_Const));
|
||||
}
|
||||
{ // test multi arg
|
||||
int x = 42;
|
||||
const double y = 3.14;
|
||||
std::string s = "abc";
|
||||
obj(42, std::move(y), s, std::string{"foo"});
|
||||
Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst);
|
||||
c_obj(42, std::move(y), s, std::string{"foo"});
|
||||
Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const);
|
||||
}
|
||||
{ // call as rvalue test. This should not invoke the functor as an rvalue.
|
||||
std::move(obj)();
|
||||
assert(Fn::check_call<>(CT_NonConst));
|
||||
std::move(c_obj)();
|
||||
assert(Fn::check_call<>(CT_Const));
|
||||
}
|
||||
}
|
||||
|
||||
void call_operator_noexcept_test()
|
||||
{
|
||||
{
|
||||
using T = ConstCallable<bool>;
|
||||
T value(true);
|
||||
auto ret = std::not_fn(value);
|
||||
static_assert(!noexcept(ret()), "call should not be noexcept");
|
||||
auto const& cret = ret;
|
||||
static_assert(!noexcept(cret()), "call should not be noexcept");
|
||||
}
|
||||
{
|
||||
using T = NoExceptCallable<bool>;
|
||||
T value(true);
|
||||
auto ret = std::not_fn(value);
|
||||
static_assert(noexcept(!_VSTD::__invoke(value)), "");
|
||||
static_assert(noexcept(ret()), "call should be noexcept");
|
||||
auto const& cret = ret;
|
||||
static_assert(noexcept(cret()), "call should be noexcept");
|
||||
}
|
||||
{
|
||||
using T = NoExceptCallable<EvilBool>;
|
||||
T value(true);
|
||||
auto ret = std::not_fn(value);
|
||||
static_assert(!noexcept(ret()), "call should not be noexcept");
|
||||
auto const& cret = ret;
|
||||
static_assert(!noexcept(cret()), "call should not be noexcept");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constructor_tests();
|
||||
return_type_tests();
|
||||
other_callable_types_test();
|
||||
throws_in_constructor_test();
|
||||
call_operator_sfinae_test(); // somewhat of an extension
|
||||
call_operator_forwarding_test();
|
||||
call_operator_noexcept_test();
|
||||
}
|
|
@ -81,9 +81,9 @@
|
|||
<tr><td><a href="http://wg21.link/P0024R2">P0024R2</a></td><td>LWG</td><td>The Parallelism TS Should be Standardized</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0226R1">P0226R1</a></td><td>LWG</td><td>Mathematical Special Functions for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0220R1">P0220R1</a></td><td>LWG</td><td>Adopt Library Fundamentals V1 TS Components for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0218R1">P0218R1</a></td><td>LWG</td><td>Adopt the File System TS for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0218R1">P0218R1</a></td><td>LWG</td><td>Adopt the File System TS for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0033R1">P0033R1</a></td><td>LWG</td><td>Re-enabling shared_from_this</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0005R4">P0005R4</a></td><td>LWG</td><td>Adopt not_fn from Library Fundamentals 2 for C++17</td><td>Jacksonville</td><td></td><td></td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0005R4">P0005R4</a></td><td>LWG</td><td>Adopt not_fn from Library Fundamentals 2 for C++17</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0152R1">P0152R1</a></td><td>LWG</td><td>constexpr atomic::is_always_lock_free</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0185R1">P0185R1</a></td><td>LWG</td><td>Adding [nothrow-]swappable traits</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
|
||||
<tr><td><a href="http://wg21.link/P0253R1">P0253R1</a></td><td>LWG</td><td>Fixing a design mistake in the searchers interface</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
|
||||
|
|
Loading…
Reference in New Issue