Define std::not_fn for C++17
authorJonathan Wakely <jwakely@redhat.com>
Fri, 19 Aug 2016 15:42:34 +0000 (16:42 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 19 Aug 2016 15:42:34 +0000 (16:42 +0100)
* 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
libstdc++-v3/doc/html/manual/status.html
libstdc++-v3/doc/xml/manual/status_cxx2017.xml
libstdc++-v3/include/experimental/functional
libstdc++-v3/include/std/functional
libstdc++-v3/testsuite/20_util/not_fn/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/functional/not_fn.cc

index 727285a..5239600 100644 (file)
@@ -1,5 +1,14 @@
 2016-08-19  Jonathan Wakely  <jwakely@redhat.com>
 
+       * 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.
index 6460639..e82739a 100644 (file)
@@ -578,11 +578,11 @@ Feature-testing recommendations for C++</a>.
        <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4277.html" target="_top">
          N4277
        </a>
-      </td><td align="center"> 5.1 </td><td align="left"> </td></tr><tr bgcolor="#C8B0B0"><td align="left"> Adopt <code class="code">not_fn</code> from Library Fundamentals 2 for C++17 </td><td align="left">
+      </td><td align="center"> 5.1 </td><td align="left"> </td></tr><tr><td align="left"> Adopt <code class="code">not_fn</code> from Library Fundamentals 2 for C++17 </td><td align="left">
        <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0005r4.html" target="_top">
        P0005R4
        </a>
-      </td><td align="center"> No </td><td align="left"><code class="code">__cpp_lib_not_fn &gt;= 201603</code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> Fixes for <code class="code">not_fn</code> </td><td align="left">
+      </td><td align="center"> 7 </td><td align="left"><code class="code">__cpp_lib_not_fn &gt;= 201603</code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> Fixes for <code class="code">not_fn</code> </td><td align="left">
        <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0358r1.html" target="_top">
        P0358R1
        </a>
index 331420e..ff96627 100644 (file)
@@ -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>
 
index ed41f5a..eddbcf1 100644 (file)
@@ -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
index 8608134..87d1c17 100644 (file)
@@ -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 (file)
index 0000000..375c7cc
--- /dev/null
@@ -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();
+}
index 3096eaa..1b3adf1 100644 (file)
@@ -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();
 }