Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions stl/inc/functional
Original file line number Diff line number Diff line change
Expand Up @@ -1557,24 +1557,18 @@ constexpr auto _Call_front_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tup
template <class _Fx, class... _Types>
class _Front_binder { // wrap bound callable object and arguments
private:
static_assert(is_constructible_v<decay_t<_Fx>, _Fx>,
"std::bind_front() requires the decayed callable to be constructible from an undecayed callable");
static_assert(is_move_constructible_v<decay_t<_Fx>>,
"std::bind_front() requires the decayed callable to be move constructible");
static_assert(conjunction_v<is_constructible<decay_t<_Types>, _Types>...>,
"std::bind_front() requires the decayed bound arguments to be constructible from undecayed bound arguments");
static_assert(conjunction_v<is_move_constructible<decay_t<_Types>>...>,
"std::bind_front() requires the decayed bound arguments to be move constructible");
using _Seq = index_sequence_for<_Types...>;

using _Seq = index_sequence_for<_Types...>;
using _First = decay_t<_Fx>;
using _Second = tuple<decay_t<_Types>...>;
_Compressed_pair<_Fx, tuple<_Types...>> _Mypair;

_Compressed_pair<_First, _Second> _Mypair;
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Fx, decay_t<_Fx>>);
_STL_INTERNAL_STATIC_ASSERT((is_same_v<_Types, decay_t<_Types>> && ...));

public:
constexpr explicit _Front_binder(_Fx&& _Func, _Types&&... _Args)
: _Mypair(_One_then_variadic_args_t{}, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) {}
template <class _FxInit, class... _TypesInit,
enable_if_t<sizeof...(_TypesInit) != 0 || !is_same_v<remove_cvref_t<_FxInit>, _Front_binder>, int> = 0>
constexpr explicit _Front_binder(_FxInit&& _Func, _TypesInit&&... _Args)
: _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {}

template <class... _Unbound>
constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(noexcept(
Expand Down Expand Up @@ -1614,7 +1608,16 @@ public:
// FUNCTION TEMPLATE bind_front
template <class _Fx, class... _Types>
_NODISCARD constexpr auto bind_front(_Fx&& _Func, _Types&&... _Args) {
return _Front_binder<_Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
static_assert(is_constructible_v<decay_t<_Fx>, _Fx>,
"std::bind_front requires the decayed callable to be constructible from an undecayed callable");
static_assert(is_move_constructible_v<decay_t<_Fx>>,
"std::bind_front requires the decayed callable to be move constructible");
static_assert(conjunction_v<is_constructible<decay_t<_Types>, _Types>...>,
"std::bind_front requires the decayed bound arguments to be constructible from undecayed bound arguments");
static_assert(conjunction_v<is_move_constructible<decay_t<_Types>>...>,
"std::bind_front requires the decayed bound arguments to be move constructible");

return _Front_binder<decay_t<_Fx>, decay_t<_Types>...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}
#endif // _HAS_CXX20

Expand Down
61 changes: 61 additions & 0 deletions tests/std/tests/P0356R5_bind_front/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,65 @@ int main() {
auto bound7 = move(bound6);
assert(*move(bound6)() == -9000);
assert(*move(bound7)() == 1234);

// Also test GH-1292 "bind_front violates [func.require]p8" in which the return type of bind_front inadvertently
// depends on the value category and/or cv-qualification of its arguments.
{
struct S {
int i = 42;
};
S s;
auto lambda = [](S x) { return x.i; };
auto returns_lambda = [=] { return lambda; };
auto returns_const_lambda = [=]() -> const decltype(lambda) { return lambda; };
auto returns_const_S = []() -> const S { return {}; };

using T = decltype(bind_front(lambda, s));
static_assert(is_same_v<decltype(bind_front(lambda, move(s))), T>);
static_assert(is_same_v<decltype(bind_front(lambda, S{})), T>);

static_assert(is_same_v<decltype(bind_front(move(lambda), s)), T>);
static_assert(is_same_v<decltype(bind_front(move(lambda), move(s))), T>);
static_assert(is_same_v<decltype(bind_front(move(lambda), S{})), T>);

static_assert(is_same_v<decltype(bind_front(returns_lambda(), s)), T>);
static_assert(is_same_v<decltype(bind_front(returns_lambda(), move(s))), T>);
static_assert(is_same_v<decltype(bind_front(returns_lambda(), S{})), T>);

static_assert(is_same_v<decltype(bind_front(lambda, as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(lambda, move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(lambda, returns_const_S())), T>);

static_assert(is_same_v<decltype(bind_front(move(lambda), as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(move(lambda), move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(move(lambda), returns_const_S())), T>);

static_assert(is_same_v<decltype(bind_front(returns_lambda(), as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(returns_lambda(), move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(returns_lambda(), returns_const_S())), T>);

static_assert(is_same_v<decltype(bind_front(as_const(lambda), s)), T>);
static_assert(is_same_v<decltype(bind_front(as_const(lambda), move(s))), T>);
static_assert(is_same_v<decltype(bind_front(as_const(lambda), S{})), T>);

static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), s)), T>);
static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), move(s))), T>);
static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), S{})), T>);

static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), s)), T>);
static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), move(s))), T>);
static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), S{})), T>);

static_assert(is_same_v<decltype(bind_front(as_const(lambda), as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(as_const(lambda), move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(as_const(lambda), returns_const_S())), T>);

static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(move(as_const(lambda)), returns_const_S())), T>);

static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), as_const(s))), T>);
static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), move(as_const(s)))), T>);
static_assert(is_same_v<decltype(bind_front(returns_const_lambda(), returns_const_S())), T>);
}
}