* 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
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.
<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 >= 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 >= 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>
</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>
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
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
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
--- /dev/null
+// 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();
+}
bool operator()() { return false; }
bool operator()() const { return true; }
bool operator()(int) { return false; }
- bool operator()(int) volatile { return true; }
};
void
VERIFY( f3(1) == true );
const auto f4 = f3;
VERIFY( f4() == false );
- volatile auto f5 = f3;
- VERIFY( f5(1) == false );
}
template<typename F, typename Arg>
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();
}