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:
parent
387edf83a0
commit
e6ee5bfd68
7 changed files with 211 additions and 28 deletions
|
@ -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.
|
||||
|
|
|
@ -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 >= 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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
94
libstdc++-v3/testsuite/20_util/not_fn/1.cc
Normal file
94
libstdc++-v3/testsuite/20_util/not_fn/1.cc
Normal 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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue