diff --git a/stl/inc/functional b/stl/inc/functional index 05b969b5ef2..da251c1bd5a 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1557,24 +1557,18 @@ constexpr auto _Call_front_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tup template class _Front_binder { // wrap bound callable object and arguments private: - static_assert(is_constructible_v, _Fx>, - "std::bind_front() requires the decayed callable to be constructible from an undecayed callable"); - static_assert(is_move_constructible_v>, - "std::bind_front() requires the decayed callable to be move constructible"); - static_assert(conjunction_v, _Types>...>, - "std::bind_front() requires the decayed bound arguments to be constructible from undecayed bound arguments"); - static_assert(conjunction_v>...>, - "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...>; + _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 , _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 constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(noexcept( @@ -1614,7 +1608,16 @@ public: // FUNCTION TEMPLATE bind_front template _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, _Fx>, + "std::bind_front requires the decayed callable to be constructible from an undecayed callable"); + static_assert(is_move_constructible_v>, + "std::bind_front requires the decayed callable to be move constructible"); + static_assert(conjunction_v, _Types>...>, + "std::bind_front requires the decayed bound arguments to be constructible from undecayed bound arguments"); + static_assert(conjunction_v>...>, + "std::bind_front requires the decayed bound arguments to be move constructible"); + + return _Front_binder, decay_t<_Types>...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...); } #endif // _HAS_CXX20 diff --git a/tests/std/tests/P0356R5_bind_front/test.cpp b/tests/std/tests/P0356R5_bind_front/test.cpp index 804997e3b42..804c9c3bb6f 100644 --- a/tests/std/tests/P0356R5_bind_front/test.cpp +++ b/tests/std/tests/P0356R5_bind_front/test.cpp @@ -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); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + + static_assert(is_same_v); + static_assert(is_same_v); + static_assert(is_same_v); + } }