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
This commit is contained in:
Jonathan Wakely 2016-08-19 16:42:34 +01:00 committed by Jonathan Wakely
parent 387edf83a0
commit e6ee5bfd68
7 changed files with 211 additions and 28 deletions

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

View 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>

View 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>

View 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

View 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

View File

@ -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();
}

View 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();
}