Index: include/functional =================================================================== --- include/functional +++ include/functional @@ -229,6 +229,9 @@ unspecified bind(Fn&&, BoundArgs&&...); template unspecified bind(Fn&&, BoundArgs&&...); + +template + unspecified bind_front(F&&, Args&&...); template invoke_result_t invoke(F&& f, Args&&... args) // C++17 @@ -2969,6 +2972,53 @@ } } +#if _LIBCPP_STD_VER > 17 + +template +auto +__bind_front_apply_both(_Fun&& __f, + _TupleArgs&& __tuple_args, _VSTD::index_sequence<_Sz...>, + _OtherArgs... __other_args) +{ + return _VSTD::invoke(_VSTD::forward<_Fun>(__f), + _VSTD::get<_Sz>(_VSTD::forward<_TupleArgs>(__tuple_args))..., + _VSTD::forward<_OtherArgs>(__other_args)...); +} + +template +struct __bind_front_impl +{ + _Fun __f; + _VSTD::tuple<_BoundArgs...> __bound_args; + + __bind_front_impl(_Fun&& __f, _BoundArgs&&... __bound_args) : + __f(_VSTD::forward<_Fun>(__f)), + __bound_args(_VSTD::forward<_BoundArgs>(__bound_args)...) { } + + template + _VSTD::invoke_result_t<_Fun&, _BoundArgs&..., _CallArgs...> + operator()(_CallArgs&&... __call_agrs) + { + auto constexpr __size = _VSTD::tuple_size_v< + typename _VSTD::remove_reference::type + >; + + return __bind_front_apply_both(__f, + __bound_args, _VSTD::make_index_sequence<__size>(), + _VSTD::forward<_CallArgs>(__call_agrs)...); + } +}; + +template +auto bind_front(_Func&& __f, _Args&&... __args) +{ + static_assert(sizeof...(_Args) > 0); + return __bind_front_impl<_VSTD::decay_t<_Func>, _Args...> + { _VSTD::forward<_Func>(__f), _VSTD::forward<_Args>(__args)... }; +} + +#endif // _LIBCPP_STD_VER > 17 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUNCTIONAL Index: test/std/utilities/function.objects/func.bind_front/bind_front.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/function.objects/func.bind_front/bind_front.fail.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// functional + +// template unspecified bind_front(F&&, Args&&...); + +#include + +constexpr int pass(const int n) { return n; } + +int simple(int n) { return n; } + +template +T do_nothing(T t) { return t; } + +int main(int, char**) +{ + int n = 1; + const int c = 1; + + auto p = std::bind_front(pass, c); + static_assert(p() == 1); // expected-error {{static_assert expression is not an integral constant expression}} + + auto d = std::bind_front(do_nothing, n); // expected-error {{no matching function for call to 'bind_front'}} + assert(d() == n); + + auto a = std::bind_front(simple); // expected-error {{static_assert failed}} + assert(a(1) == 1); +} \ No newline at end of file Index: test/std/utilities/function.objects/func.bind_front/bind_front.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/function.objects/func.bind_front/bind_front.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// functional + +// template unspecified bind_front(F&&, Args&&...); + +#include + +int add (int a, int b) { return a + b; } + +int long_test (int a, int b, int c, int d, int e, int f) +{ + return a + b + c + d + e + f; +} + +struct S { bool operator()(int a) { return a == 1; } }; + +int main(int, char**) +{ + int n = 2; + int m = 1; + + auto a = std::bind_front(add, m, n); + assert(a() == 3); + + auto b = std::bind_front(long_test, m, n, m, m, m, m); + assert(b() == 7); + + auto c = std::bind_front(long_test, n, m); + assert(c(1, 1, 1, 1) == 7); + + auto d = std::bind_front(S{}, m); + assert(d()); + + auto f = std::bind_front(add, n); + assert(f(3) == 5); +} \ No newline at end of file