std::forward<_BoundArgs>(__args)...);
}
+#if __cplusplus > 201703L
+#define __cpp_lib_bind_front 201902L
+
+ template<typename _Fd, typename... _BoundArgs>
+ struct _Bind_front
+ {
+ static_assert(is_move_constructible_v<_Fd>);
+ static_assert((is_move_constructible_v<_BoundArgs> && ...));
+
+ // First parameter is to ensure this constructor is never used
+ // instead of the copy/move constructor.
+ template<typename _Fn, typename... _Args>
+ explicit constexpr
+ _Bind_front(int, _Fn&& __fn, _Args&&... __args)
+ noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
+ is_nothrow_constructible<_BoundArgs, _Args>...>::value)
+ : _M_fd(std::forward<_Fn>(__fn)),
+ _M_bound_args(std::forward<_Args>(__args)...)
+ { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
+
+ _Bind_front(const _Bind_front&) = default;
+ _Bind_front(_Bind_front&&) = default;
+ _Bind_front& operator=(const _Bind_front&) = default;
+ _Bind_front& operator=(_Bind_front&&) = default;
+ ~_Bind_front() = default;
+
+ template<typename... _CallArgs>
+ constexpr
+ invoke_result_t<_Fd&, _BoundArgs&..., _CallArgs...>
+ operator()(_CallArgs&&... __call_args) &
+ noexcept(is_nothrow_invocable_v<_Fd&, _BoundArgs&..., _CallArgs...>)
+ {
+ return _S_call(*this, _BoundIndices(),
+ std::forward<_CallArgs>(__call_args)...);
+ }
+
+ template<typename... _CallArgs>
+ constexpr
+ invoke_result_t<const _Fd&, const _BoundArgs&..., _CallArgs...>
+ operator()(_CallArgs&&... __call_args) const &
+ noexcept(is_nothrow_invocable_v<const _Fd&, const _BoundArgs&...,
+ _CallArgs...>)
+ {
+ return _S_call(*this, _BoundIndices(),
+ std::forward<_CallArgs>(__call_args)...);
+ }
+
+ template<typename... _CallArgs>
+ constexpr
+ invoke_result_t<_Fd, _BoundArgs..., _CallArgs...>
+ operator()(_CallArgs&&... __call_args) &&
+ noexcept(is_nothrow_invocable_v<_Fd, _BoundArgs..., _CallArgs...>)
+ {
+ return _S_call(std::move(*this), _BoundIndices(),
+ std::forward<_CallArgs>(__call_args)...);
+ }
+
+ template<typename... _CallArgs>
+ constexpr
+ invoke_result_t<const _Fd, const _BoundArgs..., _CallArgs...>
+ operator()(_CallArgs&&... __call_args) const &&
+ noexcept(is_nothrow_invocable_v<const _Fd, const _BoundArgs...,
+ _CallArgs...>)
+ {
+ return _S_call(std::move(*this), _BoundIndices(),
+ std::forward<_CallArgs>(__call_args)...);
+ }
+
+ private:
+ using _BoundIndices = index_sequence_for<_BoundArgs...>;
+
+ template<typename _Tp, size_t... _Ind, typename... _CallArgs>
+ static constexpr
+ decltype(auto)
+ _S_call(_Tp&& __g, index_sequence<_Ind...>, _CallArgs&&... __call_args)
+ {
+ return std::invoke(std::forward<_Tp>(__g)._M_fd,
+ std::get<_Ind>(std::forward<_Tp>(__g)._M_bound_args)...,
+ std::forward<_CallArgs>(__call_args)...);
+ }
+
+ _Fd _M_fd;
+ std::tuple<_BoundArgs...> _M_bound_args;
+ };
+
+ template<typename _Fn, typename... _Args>
+ using _Bind_front_t
+ = _Bind_front<decay_t<_Fn>, unwrap_ref_decay_t<_Args>...>;
+
+ template<typename _Fn, typename... _Args>
+ _Bind_front_t<_Fn, _Args...>
+ bind_front(_Fn&& __fn, _Args&&... __args)
+ noexcept(is_nothrow_constructible_v<int, _Bind_front_t<_Fn, _Args...>,
+ _Fn, _Args...>)
+ {
+ return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
+ std::forward<_Args>(__args)...);
+ }
+#endif
+
#if __cplusplus >= 201402L
/// Generalized negator.
template<typename _Fn>
--- /dev/null
+// Copyright (C) 2014-2019 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++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+#ifndef __cpp_lib_bind_front
+# error "Feature test macro for bind_front is missing"
+#elif __cpp_lib_bind_front < 201811L
+# error "Feature test macro for bind_front has wrong value"
+#endif
+
+using std::bind_front;
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_invocable_r_v;
+
+void
+test01()
+{
+ struct F { void operator()() {} };
+
+ // Arguments should be decayed:
+ static_assert(std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<int>())),
+ decltype(bind_front(std::declval<F&>(), std::declval<int&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<int>())),
+ decltype(bind_front(std::declval<const F&>(), std::declval<const int&>()))
+ >);
+
+ // Reference wrappers should be handled:
+ static_assert(!std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<int&>())),
+ decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<const int&>())),
+ decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>()))),
+ decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>())))
+ >);
+}
+
+void
+test02()
+{
+ struct quals
+ {
+ bool as_const;
+ bool as_lvalue;
+ };
+
+ struct F
+ {
+ quals operator()() & { return { false, true }; }
+ quals operator()() const & { return { true, true }; }
+ quals operator()() && { return { false, false }; }
+ quals operator()() const && { return { true, false }; }
+ };
+
+ F f;
+ auto g = bind_front(f);
+ const auto& cg = g;
+ quals q;
+
+ // constness and value category should be forwarded to the target object:
+ q = g();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ std::move(g)();
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && ! q.as_lvalue );
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int& operator()(int& i, void*) { return i; }
+ void* operator()(int, void* p) const { return p; }
+ };
+
+ int i = 5;
+ void* vp = &vp; // arbitrary void* value
+
+ auto g1 = bind_front(F{}, i); // call wrapper has bound arg of type int
+ using G1 = decltype(g1);
+ // Invoking G1& will pass g1's bound arg as int&, so calls first overload:
+ static_assert(is_invocable_r_v<int&, G1&, void*>);
+ // Invoking const G1& or G&& calls second overload:
+ static_assert(is_invocable_r_v<void*, const G1&, void*>);
+ static_assert(is_invocable_r_v<void*, G1&&, void*>);
+ void* p1 = static_cast<G1&&>(g1)(vp);
+ VERIFY( p1 == vp );
+
+ auto g2 = bind_front(F{}, std::ref(i)); // bound arg of type int&
+ using G2 = decltype(g2);
+ // Bound arg always forwarded as int& even from G2&& or const G2&
+ static_assert(is_invocable_r_v<int&, G2&, void*>);
+ static_assert(is_invocable_r_v<int&, G2&&, void*>);
+ // But cannot call first overload on const G2:
+ static_assert(is_invocable_r_v<void*, const G2&, void*>);
+ static_assert(is_invocable_r_v<void*, const G2&&, void*>);
+ int& i2 = g2(vp);
+ VERIFY( &i2 == &i );
+ int& i2r = static_cast<G2&&>(g2)(vp);
+ VERIFY( &i2r == &i );
+ void* p2 = const_cast<const G2&>(g2)(vp);
+ VERIFY( p2 == vp );
+
+ auto g3 = bind_front(F{}, std::cref(i)); // bound arg of type const int&
+ using G3 = decltype(g3);
+ // Bound arg always forwarded as const int& so can only call second overload:
+ static_assert(is_invocable_r_v<void*, G3&, void*>);
+ static_assert(is_invocable_r_v<void*, G3&&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&&, void*>);
+
+ auto g4 = bind_front(g2, nullptr);
+ using G4 = decltype(g4);
+ static_assert(is_invocable_r_v<int&, G4&>);
+ static_assert(is_invocable_r_v<int&, G4&&>);
+ static_assert(is_invocable_r_v<void*, const G4&>);
+ static_assert(is_invocable_r_v<void*, const G4&&>);
+}
+
+int f(int i, int j, int k) { return i + j + k; }
+
+void
+test04()
+{
+ auto g = bind_front(f);
+ VERIFY( g(1, 2, 3) == 6 );
+ auto g1 = bind_front(f, 1);
+ VERIFY( g1(2, 3) == 6 );
+ VERIFY( bind_front(g, 1)(2, 3) == 6 );
+ auto g2 = bind_front(f, 1, 2);
+ VERIFY( g2(3) == 6 );
+ VERIFY( bind_front(g1, 2)(3) == 6 );
+ auto g3 = bind_front(f, 1, 2, 3);
+ VERIFY( g3() == 6 );
+ VERIFY( bind_front(g2, 3)() == 6 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}