|
30 | 30 | // |
31 | 31 | // VERSION HISTORY |
32 | 32 | // |
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 |
35 | 35 | // 1.02 (2024-09-24) Allow binding to copies of source functions as per C++23 |
36 | 36 | // 1.01 (2022-09-23) Allow ufunction from a free function |
37 | 37 | // 1.00 (2020-10-15) Initial release |
@@ -91,21 +91,31 @@ class ufunction : private std::function<F> |
91 | 91 |
|
92 | 92 | template <typename FO> |
93 | 93 | 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 |
94 | 101 | template <typename FO> |
95 | 102 | ufunction& operator=(FO f) noexcept |
96 | 103 | { |
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 | + ); |
98 | 111 | return *this; |
99 | 112 | } |
100 | 113 |
|
101 | 114 | // function pointer overloads (otherwise clang and gcc complain for const_cast of function pointers) |
102 | 115 | // noexcept since we're relying on the small function optimization to kick in here |
103 | 116 | // we can also afford to disregard the copy wrapper here since function pointers are copyable |
104 | | - ufunction(F* fptr) noexcept : function(fptr) {} |
105 | 117 |
|
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) {} |
109 | 119 | ufunction& operator=(F* fptr) noexcept |
110 | 120 | { |
111 | 121 | function::operator=(fptr); |
|
0 commit comments