Skip to content

Commit 9b12acc

Browse files
committed
[ufunction] improve nullptr_t assignment
1 parent 585db0a commit 9b12acc

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

include/itlib/ufunction.hpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
//
3131
// VERSION HISTORY
3232
//
33-
// 1.03 (2026-01-15) Remove assignment operators from nullptr_t to allow
34-
// resets via the `ufunc = {}` syntax
33+
// 1.03 (2026-01-15) Move assignment from nullptr_t to the template
34+
// assignment overload to allow the `ufunc = {}` syntax
3535
// 1.02 (2024-09-24) Allow binding to copies of source functions as per C++23
3636
// 1.01 (2022-09-23) Allow ufunction from a free function
3737
// 1.00 (2020-10-15) Initial release
@@ -91,21 +91,31 @@ class ufunction : private std::function<F>
9191

9292
template <typename FO>
9393
ufunction(FO f) noexcept : function(copy_wrapper<FO>{std::move(f)}) {}
94+
95+
// this also servers to handle ufunc = nullptr_t
96+
// we use it instead of a separate assignment overload for nullptr_t, to allow us to write
97+
// we can write `ufunc = {}` which is a nice syntax for resetting
98+
// `ufunc = {}` will resolve to operator=(F* fptr) which is a tiny bit slower than assigning
99+
// nullptr_t directly (because of an additional if check) but we consider it negligible
100+
// and worth the syntactic sugar
94101
template <typename FO>
95102
ufunction& operator=(FO f) noexcept
96103
{
97-
function::operator=(copy_wrapper<FO>{std::move(f)});
104+
function::operator=(
105+
std::conditional<
106+
std::is_same<FO, std::nullptr_t>::value,
107+
std::nullptr_t,
108+
copy_wrapper<FO>
109+
>::type(std::move(f))
110+
);
98111
return *this;
99112
}
100113

101114
// function pointer overloads (otherwise clang and gcc complain for const_cast of function pointers)
102115
// noexcept since we're relying on the small function optimization to kick in here
103116
// we can also afford to disregard the copy wrapper here since function pointers are copyable
104-
ufunction(F* fptr) noexcept : function(fptr) {}
105117

106-
// this also servers to handle = nullptr_t
107-
// yes, this will make it a tiny bit slower compared to having a separate assignment overload for nullptr_t,
108-
// but without the nullptr_t overload we can write `ufunc = {}` which is a nice syntax for resetting
118+
ufunction(F* fptr) noexcept : function(fptr) {}
109119
ufunction& operator=(F* fptr) noexcept
110120
{
111121
function::operator=(fptr);

test/t-ufunction-14.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ TEST_CASE("Basic")
3030

3131
f2 = {};
3232
CHECK_FALSE(f2);
33+
34+
f2 = nullptr; // must compile
35+
CHECK_FALSE(f2);
3336
}

0 commit comments

Comments
 (0)