From e6ee5bfd688c09abebddbe39beb3422163dfafd8 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 19 Aug 2016 16:42:34 +0100 Subject: [PATCH] Define std::not_fn for C++17 * doc/xml/manual/status_cxx2017.xml: Update status of not_fn. * doc/html/*: Regenerate. * include/experimental/functional (_Not_fn, not_fn): Match C++17 semantics. * include/std/functional (_Not_fn, not_fn): Define for C++17. * testsuite/20_util/not_fn/1.cc: New. * testsuite/experimental/functional/not_fn.cc: Test abstract class. Remove test for volatile-qualified wrapper. From-SVN: r239623 --- libstdc++-v3/ChangeLog | 9 ++ libstdc++-v3/doc/html/manual/status.html | 4 +- .../doc/xml/manual/status_cxx2017.xml | 3 +- libstdc++-v3/include/experimental/functional | 46 ++++----- libstdc++-v3/include/std/functional | 68 ++++++++++++++ libstdc++-v3/testsuite/20_util/not_fn/1.cc | 94 +++++++++++++++++++ .../experimental/functional/not_fn.cc | 15 ++- 7 files changed, 211 insertions(+), 28 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/not_fn/1.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 727285a8043..5239600749c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2016-08-19 Jonathan Wakely + * doc/xml/manual/status_cxx2017.xml: Update status of not_fn. + * doc/html/*: Regenerate. + * include/experimental/functional (_Not_fn, not_fn): Match C++17 + semantics. + * include/std/functional (_Not_fn, not_fn): Define for C++17. + * testsuite/20_util/not_fn/1.cc: New. + * testsuite/experimental/functional/not_fn.cc: Test abstract class. + Remove test for volatile-qualified wrapper. + * include/std/atomic (atomic::is_always_lock_free): Define. * testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno. * testsuite/29_atomics/atomic/is_always_lock_free.cc: New. diff --git a/libstdc++-v3/doc/html/manual/status.html b/libstdc++-v3/doc/html/manual/status.html index 64606393711..e82739aa1ce 100644 --- a/libstdc++-v3/doc/html/manual/status.html +++ b/libstdc++-v3/doc/html/manual/status.html @@ -578,11 +578,11 @@ Feature-testing recommendations for C++. N4277 - 5.1   Adopt not_fn from Library Fundamentals 2 for C++17 + 5.1   Adopt not_fn from Library Fundamentals 2 for C++17 P0005R4 - No __cpp_lib_not_fn >= 201603 Fixes for not_fn + 7 __cpp_lib_not_fn >= 201603 Fixes for not_fn P0358R1 diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index 331420ef3ce..ff966272311 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -321,14 +321,13 @@ Feature-testing recommendations for C++. - Adopt not_fn from Library Fundamentals 2 for C++17 P0005R4 - No + 7 __cpp_lib_not_fn >= 201603 diff --git a/libstdc++-v3/include/experimental/functional b/libstdc++-v3/include/experimental/functional index ed41f5a3982..eddbcf11c9c 100644 --- a/libstdc++-v3/include/experimental/functional +++ b/libstdc++-v3/include/experimental/functional @@ -386,41 +386,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: template explicit - _Not_fn(_Fn2&& __fn) : _M_fn(std::forward<_Fn2>(__fn)) { } + _Not_fn(_Fn2&& __fn) + : _M_fn(std::forward<_Fn2>(__fn)) { } _Not_fn(const _Not_fn& __fn) = default; _Not_fn(_Not_fn&& __fn) = default; - _Not_fn& operator=(const _Not_fn& __fn) = default; - _Not_fn& operator=(_Not_fn&& __fn) = default; ~_Not_fn() = default; template auto - operator()(_Args&&... __args) - noexcept(noexcept(!_M_fn(std::forward<_Args>(__args)...))) - -> decltype(!_M_fn(std::forward<_Args>(__args)...)) - { return !_M_fn(std::forward<_Args>(__args)...); } + operator()(_Args&&... __args) & + noexcept(__is_nothrow_callable<_Fn&(_Args&&...)>::value) + -> decltype(!std::declval>()) + { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } template auto - operator()(_Args&&... __args) const - noexcept(noexcept(!_M_fn(std::forward<_Args>(__args)...))) - -> decltype(!_M_fn(std::forward<_Args>(__args)...)) - { return !_M_fn(std::forward<_Args>(__args)...); } + operator()(_Args&&... __args) const & + noexcept(__is_nothrow_callable::value) + -> decltype(!std::declval>()) + { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } template auto - operator()(_Args&&... __args) volatile - noexcept(noexcept(!_M_fn(std::forward<_Args>(__args)...))) - -> decltype(!_M_fn(std::forward<_Args>(__args)...)) - { return !_M_fn(std::forward<_Args>(__args)...); } + operator()(_Args&&... __args) && + noexcept(__is_nothrow_callable<_Fn&&(_Args&&...)>::value) + -> decltype(!std::declval>()) + { + return !std::__invoke(std::move(_M_fn), + std::forward<_Args>(__args)...); + } template auto - operator()(_Args&&... __args) const volatile - noexcept(noexcept(!_M_fn(std::forward<_Args>(__args)...))) - -> decltype(!_M_fn(std::forward<_Args>(__args)...)) - { return !_M_fn(std::forward<_Args>(__args)...); } + operator()(_Args&&... __args) const && + noexcept(__is_nothrow_callable::value) + -> decltype(!std::declval>()) + { + return !std::__invoke(std::move(_M_fn), + std::forward<_Args>(__args)...); + } }; /// [func.not_fn] Function template not_fn @@ -429,8 +434,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION not_fn(_Fn&& __fn) noexcept(std::is_nothrow_constructible, _Fn&&>::value) { - using __maybe_type = _Maybe_wrap_member_pointer>; - return _Not_fn{std::forward<_Fn>(__fn)}; + return _Not_fn>{std::forward<_Fn>(__fn)}; } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 86081346cf6..87d1c17d166 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -2129,6 +2129,74 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) swap(function<_Res(_Args...)>& __x, function<_Res(_Args...)>& __y) { __x.swap(__y); } + +#if __cplusplus > 201402L + +#define __cpp_lib_not_fn 201603 + + /// Generalized negator. + template + class _Not_fn + { + public: + template + explicit + _Not_fn(_Fn2&& __fn) + : _M_fn(std::forward<_Fn2>(__fn)) { } + + _Not_fn(const _Not_fn& __fn) = default; + _Not_fn(_Not_fn&& __fn) = default; + ~_Not_fn() = default; + + template + auto + operator()(_Args&&... __args) & + noexcept(is_nothrow_callable_v<_Fn&(_Args&&...)>) + -> decltype(!std::declval>()) + { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } + + template + auto + operator()(_Args&&... __args) const & + noexcept(is_nothrow_callable_v) + -> decltype(!std::declval>()) + { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); } + + template + auto + operator()(_Args&&... __args) && + noexcept(is_nothrow_callable_v<_Fn&&(_Args&&...)>) + -> decltype(!std::declval>()) + { + return !std::__invoke(std::move(_M_fn), + std::forward<_Args>(__args)...); + } + + template + auto + operator()(_Args&&... __args) const && + noexcept(is_nothrow_callable_v) + -> decltype(!std::declval>()) + { + return !std::__invoke(std::move(_M_fn), + std::forward<_Args>(__args)...); + } + + private: + _Fn _M_fn; + }; + + /// [func.not_fn] Function template not_fn + template + inline auto + not_fn(_Fn&& __fn) + noexcept(std::is_nothrow_constructible, _Fn&&>::value) + { + return _Not_fn>{std::forward<_Fn>(__fn)}; + } + +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/testsuite/20_util/not_fn/1.cc b/libstdc++-v3/testsuite/20_util/not_fn/1.cc new file mode 100644 index 00000000000..375c7cc1367 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/not_fn/1.cc @@ -0,0 +1,94 @@ +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17" } + +#include +#include + +using std::not_fn; + +int func(int, char) { return 0; } + +struct F +{ + bool operator()() { return false; } + bool operator()() const { return true; } + bool operator()(int) { return false; } +}; + +void +test01() +{ + auto f1 = not_fn(func); + VERIFY( f1(1, '2') == true ); + + auto f2 = not_fn( [] { return true; } ); + VERIFY( f2() == false ); + + auto f3 = not_fn( F{} ); + VERIFY( f3() == true ); + VERIFY( f3(1) == true ); + const auto f4 = f3; + VERIFY( f4() == false ); +} + +template +auto foo(F f, Arg arg) -> decltype(not_fn(f)(arg)) { return not_fn(f)(arg); } + +template +auto foo(F f, Arg arg) -> decltype(not_fn(f)()) { return not_fn(f)(); } + +struct negator +{ + bool operator()(int) const { return false; } + void operator()() const {} +}; + +void +test02() +{ + foo(negator{}, 1); // PR libstdc++/66998 +} + +void +test03() +{ + struct X { bool b; }; + X x{ false }; + VERIFY( not_fn(&X::b)(x) ); +} + +void +test04() +{ + struct abstract { virtual void f() = 0; }; + struct derived : abstract { void f() { } }; + struct F { bool operator()(abstract&) { return false; } }; + F f; + derived d; + VERIFY( not_fn(f)(d) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/experimental/functional/not_fn.cc b/libstdc++-v3/testsuite/experimental/functional/not_fn.cc index 3096eaae79e..1b3adf10899 100644 --- a/libstdc++-v3/testsuite/experimental/functional/not_fn.cc +++ b/libstdc++-v3/testsuite/experimental/functional/not_fn.cc @@ -29,7 +29,6 @@ struct F bool operator()() { return false; } bool operator()() const { return true; } bool operator()(int) { return false; } - bool operator()(int) volatile { return true; } }; void @@ -46,8 +45,6 @@ test01() VERIFY( f3(1) == true ); const auto f4 = f3; VERIFY( f4() == false ); - volatile auto f5 = f3; - VERIFY( f5(1) == false ); } template @@ -76,10 +73,22 @@ test03() VERIFY( not_fn(&X::b)(x) ); } +void +test04() +{ + struct abstract { virtual void f() = 0; }; + struct derived : abstract { void f() { } }; + struct F { bool operator()(abstract&) { return false; } }; + F f; + derived d; + VERIFY( not_fn(f)(d) ); +} + int main() { test01(); test02(); test03(); + test04(); } -- 2.30.2