]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Use deducing this in std::not_fn when available [PR111327]
authorPatrick Palka <ppalka@redhat.com>
Fri, 5 Dec 2025 17:14:23 +0000 (12:14 -0500)
committerPatrick Palka <ppalka@redhat.com>
Fri, 5 Dec 2025 17:14:23 +0000 (12:14 -0500)
Implement the perfect forwarding required by std::not_fn using deducing
this when available, instead of needing 8 operator() overloads.  This
also fixes Jiang An's test from this PR which would be messy to fix in
the old implementation.

PR libstdc++/111327

libstdc++-v3/ChangeLog:

* include/std/functional (_Not_fn::operator())
[_GLIBCXX_EXPLICIT_THIS_PARAMETER]: Define as a single
overload using deducing this.
* testsuite/20_util/function_objects/not_fn/111327.cc: Extend test.

Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
libstdc++-v3/include/std/functional
libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc

index 1928a27d3fd66d5587df549a1578052521041d0b..69a3910b0bd9b432b5d2765774935b0edd2b997d 100644 (file)
@@ -1056,6 +1056,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Not_fn(_Not_fn&& __fn) = default;
       ~_Not_fn() = default;
 
+#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
+      template<typename _Self, typename... _Args>
+      _GLIBCXX20_CONSTEXPR
+      decltype(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>())
+      operator()(this _Self&& __self, _Args&&... __args)
+      noexcept(__is_nothrow_invocable<__like_t<_Self, _Fn>, _Args...>::value
+              && noexcept(_S_not<__inv_res_t<__like_t<_Self, _Fn>, _Args...>>()))
+      {
+       return !std::__invoke(__like_t<_Self, _Not_fn>(__self)._M_fn,
+                             std::forward<_Args>(__args)...);
+      }
+# pragma GCC diagnostic pop
+#else
       // Macro to define operator() with given cv-qualifiers ref-qualifiers,
       // forwarding _M_fn and the function arguments with the same qualifiers,
       // and deducing the return type and exception-specification.
@@ -1081,6 +1096,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _GLIBCXX_NOT_FN_CALL_OP( && )
       _GLIBCXX_NOT_FN_CALL_OP( const && )
 #undef _GLIBCXX_NOT_FN_CALL_OP
+#endif
 
     private:
       _Fn _M_fn;
index 725a84262716b6c8bf1e509050c55b6e39a1a842..be58b0e28d1ab9921e2eca5dd9ce9aa7b83ab88f 100644 (file)
@@ -15,15 +15,28 @@ struct G {
   bool operator()(...) const &&;
 };
 
+struct Weird {
+  void operator()();
+  bool operator()() const { return true; }
+};
+
 int main() {
   auto f = std::not_fn(F{});
-  f(); // { dg-error "deleted" }
+  f(); // { dg-error "no match" }
   std::move(f)();
   std::as_const(f)();
   std::move(std::as_const(f))();
 
   auto g = std::not_fn(G{});
-  g(); // { dg-error "deleted" }
-  std::move(g)(); // { dg-error "deleted" }
+  g(); // { dg-error "no match" }
+  std::move(g)(); // { dg-error "no match" }
   std::move(std::as_const(g))();
+
+  auto h = std::not_fn(Weird{});
+  h(); // { dg-error "no match" }
 }
+
+// { dg-error "no type named 'type' in 'struct std::__invoke_result<" "" { target *-*-* } 0 }
+// { dg-error "no matching function for call to 'std::_Not_fn<Weird>" "" { target *-*-* } 0 }
+// { dg-error "could not convert 'std::declval<void>\\(\\)' from 'void' to 'bool'" "" { target *-*-* } 0 }
+// { dg-error "in argument to unary !" "" { target *-*-* } 0 }