This updates std::experimental::not_fn to match the C++17 semantics
(which are a superset of the Library Fundamentals v2 semantics) and
then copies it to std::not_fn as well.

        * 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.

Tested x86_64-linux, committed to trunk.


commit 8014ab8c2415e84d4b9b9f9de0718633dc8ca7b8
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Fri Aug 19 12:33:13 2016 +0100

    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.

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml 
b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index 331420e..ff96627 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++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Adopt <code>not_fn</code> from Library Fundamentals 2 for C++17 
</entry>
       <entry>
        <link xmlns:xlink="http://www.w3.org/1999/xlink"; 
xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0005r4.html";>
        P0005R4
        </link>
       </entry>
-      <entry align="center"> No </entry>
+      <entry align="center"> 7 </entry>
       <entry><code>__cpp_lib_not_fn >= 201603</code></entry>
     </row>
 
diff --git a/libstdc++-v3/include/experimental/functional 
b/libstdc++-v3/include/experimental/functional
index ed41f5a..eddbcf1 100644
--- a/libstdc++-v3/include/experimental/functional
+++ b/libstdc++-v3/include/experimental/functional
@@ -386,41 +386,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     public:
       template<typename _Fn2>
        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<typename... _Args>
        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<result_of_t<_Fn&(_Args&&...)>>())
+       { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
 
       template<typename... _Args>
        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<const _Fn&(_Args&&...)>::value)
+       -> decltype(!std::declval<result_of_t<const _Fn&(_Args&&...)>>())
+       { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
 
       template<typename... _Args>
        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<result_of_t<_Fn&&(_Args&&...)>>())
+       {
+         return !std::__invoke(std::move(_M_fn),
+                               std::forward<_Args>(__args)...);
+       }
 
       template<typename... _Args>
        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<const _Fn&&(_Args&&...)>::value)
+       -> decltype(!std::declval<result_of_t<const _Fn&&(_Args&&...)>>())
+       {
+         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<std::decay_t<_Fn>, _Fn&&>::value)
     {
-      using __maybe_type = _Maybe_wrap_member_pointer<std::decay_t<_Fn>>;
-      return _Not_fn<typename __maybe_type::type>{std::forward<_Fn>(__fn)};
+      return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn)};
     }
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 8608134..87d1c17 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<typename _Fn>
+    class _Not_fn
+    {
+    public:
+      template<typename _Fn2>
+       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<typename... _Args>
+       auto
+       operator()(_Args&&... __args) &
+       noexcept(is_nothrow_callable_v<_Fn&(_Args&&...)>)
+       -> decltype(!std::declval<result_of_t<_Fn&(_Args&&...)>>())
+       { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
+
+      template<typename... _Args>
+       auto
+       operator()(_Args&&... __args) const &
+       noexcept(is_nothrow_callable_v<const _Fn&(_Args&&...)>)
+       -> decltype(!std::declval<result_of_t<const _Fn&(_Args&&...)>>())
+       { return !std::__invoke(_M_fn, std::forward<_Args>(__args)...); }
+
+      template<typename... _Args>
+       auto
+       operator()(_Args&&... __args) &&
+       noexcept(is_nothrow_callable_v<_Fn&&(_Args&&...)>)
+       -> decltype(!std::declval<result_of_t<_Fn&&(_Args&&...)>>())
+       {
+         return !std::__invoke(std::move(_M_fn),
+                               std::forward<_Args>(__args)...);
+       }
+
+      template<typename... _Args>
+       auto
+       operator()(_Args&&... __args) const &&
+       noexcept(is_nothrow_callable_v<const _Fn&&(_Args&&...)>)
+       -> decltype(!std::declval<result_of_t<const _Fn&&(_Args&&...)>>())
+       {
+         return !std::__invoke(std::move(_M_fn),
+                               std::forward<_Args>(__args)...);
+       }
+
+    private:
+      _Fn _M_fn;
+    };
+
+  /// [func.not_fn] Function template not_fn
+  template<typename _Fn>
+    inline auto
+    not_fn(_Fn&& __fn)
+    noexcept(std::is_nothrow_constructible<std::decay_t<_Fn>, _Fn&&>::value)
+    {
+      return _Not_fn<std::decay_t<_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 0000000..375c7cc
--- /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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+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<typename F, typename Arg>
+auto foo(F f, Arg arg) -> decltype(not_fn(f)(arg)) { return not_fn(f)(arg); }
+
+template<typename F, typename Arg>
+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 3096eaa..1b3adf1 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<typename F, typename Arg>
@@ -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();
 }

Reply via email to