Skip to content

Commit 328e808

Browse files
committed
Return different* function object when sizeof...(_BoundArgs) == 0
* Such that `std::is_empty_v<F>` is `true` and `operator()` is static.
1 parent 4cfab17 commit 328e808

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

libcxx/include/__functional/bind_front.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ struct __nttp_bind_front_t<_Fn, index_sequence<_Indices...>, _BoundArgs...> {
7070
}
7171
};
7272

73+
template <auto _Fn>
74+
struct __nttp_bind_without_bound_args_t {
75+
template <class... _Args>
76+
_LIBCPP_HIDE_FROM_ABI static constexpr auto
77+
operator()(_Args&&... __args) noexcept(noexcept(std::invoke(_Fn, std::forward<_Args>(__args)...)))
78+
-> decltype(std::invoke(_Fn, std::forward<_Args>(__args)...)) {
79+
return std::invoke(_Fn, std::forward<_Args>(__args)...);
80+
}
81+
};
82+
7383
template <auto _Fn, class... _Args>
7484
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto bind_front(_Args&&... __args) {
7585
static_assert((is_constructible_v<decay_t<_Args>, _Args> && ...),
@@ -79,8 +89,11 @@ template <auto _Fn, class... _Args>
7989
if constexpr (using _Ty = decltype(_Fn); is_pointer_v<_Ty> || is_member_pointer_v<_Ty>)
8090
static_assert(_Fn != nullptr, "f cannot be equal to nullptr");
8191

82-
return __nttp_bind_front_t<_Fn, index_sequence_for<_Args...>, decay_t<_Args>...>{
83-
.__bound_args_{std::forward<_Args>(__args)...}};
92+
if constexpr (sizeof...(_Args) == 0)
93+
return __nttp_bind_without_bound_args_t<_Fn>{};
94+
else
95+
return __nttp_bind_front_t<_Fn, index_sequence_for<_Args...>, decay_t<_Args>...>{
96+
.__bound_args_{std::forward<_Args>(__args)...}};
8497
}
8598

8699
#endif // _LIBCPP_STD_VER >= 26
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: std-at-least-c++26
10+
11+
// <functional>
12+
13+
// Type of `std::bind_front<NTTP>(/* no bound args */)` is empty.
14+
15+
#include <functional>
16+
#include <type_traits>
17+
18+
struct NonEmptyFunctionObject {
19+
int val = true;
20+
void operator()() const;
21+
};
22+
23+
void func();
24+
25+
struct SomeClass {
26+
long member_object;
27+
void member_function();
28+
};
29+
30+
using ResultWithEmptyFuncObject = decltype(std::bind_front<std::integral_constant<int, 0>{}>());
31+
static_assert(std::is_empty_v<ResultWithEmptyFuncObject>);
32+
33+
using ResultWithNotEmptyFuncObject = decltype(std::bind_front<NonEmptyFunctionObject{}>());
34+
static_assert(std::is_empty_v<ResultWithNotEmptyFuncObject>);
35+
36+
using ResultWithFunctionPointer = decltype(std::bind_front<func>());
37+
static_assert(std::is_empty_v<ResultWithFunctionPointer>);
38+
39+
using ResultWithMemberObjectPointer = decltype(std::bind_front<&SomeClass::member_object>());
40+
static_assert(std::is_empty_v<ResultWithMemberObjectPointer>);
41+
42+
using ResultWithMemberFunctionPointer = decltype(std::bind_front<&SomeClass::member_function>());
43+
static_assert(std::is_empty_v<ResultWithMemberFunctionPointer>);

0 commit comments

Comments
 (0)