From 4d38c00f7b271ac10eadd508a9e08b258010ba46 Mon Sep 17 00:00:00 2001 From: Kim-J-Smith <3440910457@qq.com> Date: Fri, 31 Jul 2026 21:30:47 +0800 Subject: [PATCH 01/11] ci: update test ci. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7d7827a..d5d9269 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: push: branches: [ main, version-* ] pull_request: - branches: [ main, version-* ] + branches: [ main, version-*, dev/v*.*.*/trunk ] types: [ opened, synchronize, reopened ] jobs: From effd791d0ee2418ca35ffee811c764a7e3c64e64 Mon Sep 17 00:00:00 2001 From: Kim-J-Smith <3440910457@qq.com> Date: Fri, 31 Jul 2026 23:03:35 +0800 Subject: [PATCH 02/11] V2.2.0/dev/no experimental code (#116) * chore: remove macro EMBED_FN_CONFIG_USE_BIG_DEFAULT_BUFFER. * resolve TODO. --- include/embed/embed_function.hpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/embed/embed_function.hpp b/include/embed/embed_function.hpp index 4629e90..2f79279 100644 --- a/include/embed/embed_function.hpp +++ b/include/embed/embed_function.hpp @@ -16,9 +16,6 @@ // Just like function pointers, it is quick and efficient. -/// @deprecated @b EMBED_FN_CONFIG_USE_BIG_DEFAULT_BUFFER -/// If this macro is defined, bigger default buffer size will be used. - /// @b EMBED_FN_CONFIG_DISABLE_SMART_FORWARD /// If this macro is defined, `smart_forward_t` will fall back to Perfect Forwarding. @@ -1119,14 +1116,7 @@ inline namespace fn_traits { // The buffer size for ebd::fn_ref. Stop supporting pointer-to-members. static constexpr std::size_t ref_buf = sizeof(void (*) ()); static constexpr std::size_t view_buf = ref_buf; -#if defined(EMBED_FN_CONFIG_USE_BIG_DEFAULT_BUFFER) - /// @deprecated @todo TODO: Remove this in version-2.2.0. - static constexpr std::size_t value_c1 = 6 * sizeof(void*); - static constexpr std::size_t value_c2 = sizeof(::std::function); - static constexpr std::size_t value = value_c1 > value_c2 ? value_c1 : value_c2; -#else static constexpr std::size_t value = sizeof(void (UndefinedClass::*) ()); -#endif // The alignment for owning wrappers (ebd::fn, ebd::unique_fn, ebd::safe_fn). // Using alignof(std::max_align_t) ensures that objects with the maximum @@ -1411,7 +1401,6 @@ inline namespace fn_traits { using get_member_fn_type_t = typename get_member_fn_type::type; #if __cpp_lib_reflection >= 202506L - /// @todo experimental `std::meta::is_complete_type` // Use template parameter `Val` to avoid violating ODR. template consteval bool is_complete_here() noexcept { return Val; } @@ -2887,8 +2876,6 @@ namespace crtp_mixins { #if __cpp_lib_constant_wrapper >= 202603L - /// @todo experimental - // Create function reference with given `std::constant_wrapper` param. template requires Config::isView @@ -3468,7 +3455,6 @@ namespace detail { # undef EMBED_NODISCARD # undef EMBED_DEPRECATED -# undef EMBED_FN_CONFIG_USE_BIG_DEFAULT_BUFFER # undef EMBED_FN_CONFIG_DISABLE_SMART_FORWARD # undef EMBED_FN_CONFIG_UNDEF_MACROS # undef EMBED_FN_HOOK_DEBUG From 6b4d52a597f67c265e98a6c4973d125d186b17fa Mon Sep 17 00:00:00 2001 From: Kim-J-Smith <3440910457@qq.com> Date: Sun, 2 Aug 2026 00:56:11 +0800 Subject: [PATCH 03/11] Remove `safe_fn`, refactor `fn`/`unique_fn`, and add `classic_fn`. (#117) * refactor: WIP: refactor fn, fn_ref. deprecated safe_fn and add classic_fn. * feat: propagate noexcept qualifiers through make_fn and allow noexcept signatures for fn/unique_fn * chore: remove view_buf and update documents. * chore: remove outdate comments. * docs: update documents. * resolve review comments. * style: rename noexcept_qualify_like as get_correct_signature --- README.md | 38 ++-- docs/api/basic_fn.md | 4 +- docs/api/classic_fn.md | 73 +++++++ docs/api/detail/function.md | 2 +- docs/api/fn.md | 6 +- docs/api/fn_ref.md | 2 +- docs/api/make_fn.md | 41 ++-- docs/api/safe_fn.md | 85 ++------ docs/api/unique_fn.md | 6 +- example/basic_usage.cpp | 12 +- include/embed/embed_function.hpp | 182 ++++++++---------- test/CMakeLists.txt | 1 - .../fail/assign_noexcept.1.fail.cpp | 4 +- .../fail/assign_noexcept.2.fail.cpp | 4 +- .../fn_ref/conformance.addition.pass.cpp | 4 +- .../safe_fn/fail/not_assert_nothrow.fail.cpp | 14 -- test/test_AssignAndConvert.cpp | 31 ++- test/test_BasicAttributes.cpp | 74 ++++--- test/test_InitFunction.cpp | 42 +++- test/test_Lifetime.cpp | 10 +- test/test_Swap.cpp | 12 +- test/test_ThrowDeath.cpp | 38 ++-- test/test_UnaryDereference.cpp | 76 ++++++++ test/test_function.hpp | 2 + 24 files changed, 418 insertions(+), 345 deletions(-) create mode 100644 docs/api/classic_fn.md rename test/conformance/{safe_fn => fn}/fail/assign_noexcept.1.fail.cpp (64%) rename test/conformance/{safe_fn => fn}/fail/assign_noexcept.2.fail.cpp (65%) delete mode 100644 test/conformance/safe_fn/fail/not_assert_nothrow.fail.cpp diff --git a/README.md b/README.md index 9331e60..64de259 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ template template class unique_fn; // Wrapper for movable, especially move-only callable objects. template - class safe_fn; // Wrapper for copyable callable objects which assert no-throw in Ctor and Dtor. + class classic_fn; // Wrapper for copyable callable objects (throws on empty, like std::function). template class fn_ref; // View (non-owning wrapper) for callable objects. } @@ -89,7 +89,7 @@ auto main() -> int { // Callable object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| ``` -- *`Function wrapper`*: One of `ebd::fn`, `ebd::unique_fn`, `ebd::safe_fn` and `ebd::fn_ref`. +- *`Function wrapper`*: One of `ebd::fn`, `ebd::unique_fn`, `ebd::classic_fn` and `ebd::fn_ref`. - *`Return type`*: A type that can be implicitly converted from the direct return type of *`Callable object`*. @@ -126,7 +126,7 @@ auto main() -> int { - Provide a view or reference to the callable object, referring to the [`std::function_ref` P0792](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0792r14.html). - - Following the above design goals, `ebd::fn`, `ebd::unique_fn`, `ebd::safe_fn` and `ebd::fn_ref` were designed for developers to use. + - Following the above design goals, `ebd::fn`, `ebd::unique_fn`, `ebd::classic_fn` and `ebd::fn_ref` were designed for developers to use. ## ✨ Core function wrappers @@ -134,19 +134,19 @@ auto main() -> int { | Wrapper Type | Copyable | View (Non-owning) | Throws on Empty Call | Assert No-Throw (Ctor/Dtor) | Buffer Size | Primary Use Case | | :----------- | :---: | :---: | :---: | :---: | :---: | :---: | -| [`ebd::fn`](./docs/api/fn.md) | Yes | No | Yes (`std::bad_function_call`) | No | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Copyable callable wrapper | -| [`ebd::unique_fn`](./docs/api/unique_fn.md) | No | No | Yes (`std::bad_function_call`) | No | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Move-only callable wrapper | -| [`ebd::safe_fn`](./docs/api/safe_fn.md) | Yes | No | No (`std::terminate()`) | Yes | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Exception-safe copyable callable wrapper | +| [`ebd::fn`](./docs/api/fn.md) | Yes | No | No (`std::terminate()`) | No | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Copyable callable wrapper | +| [`ebd::unique_fn`](./docs/api/unique_fn.md) | No | No | No (`std::terminate()`) | No | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Move-only callable wrapper | +| [`ebd::classic_fn`](./docs/api/classic_fn.md) | Yes | No | Yes (`std::bad_function_call`) | No | Configurable (aligned, default: `sizeof(void(Class::*)())`) | Classic wrapper (like `std::function`) | | [`ebd::fn_ref`](./docs/api/fn_ref.md) | Yes | Yes | No (*NO EMPTY STATE*) | No | Fixed | Lightweight non-owning reference(view) of callables | | [`ebd::basic_fn`](./docs/api/basic_fn.md) | - | - | - | - | - | Customized by the user | ### Key takeaways -1. **Ownership & Copy**: `fn`/`safe_fn` own callables (copyable), `unique_fn` owns but is move-only, `fn_ref` is non-owning (view). +1. **Ownership & Copy**: `fn`/`classic_fn` own callables (copyable), `unique_fn` owns but is move-only, `fn_ref` is non-owning (view). -2. **Exception Behavior**: Only `fn`/`unique_fn` throw on empty calls; `safe_fn`/`fn_ref` terminate (no exceptions). +2. **Exception Behavior**: `fn`/`unique_fn` terminate on empty calls (no exceptions); `classic_fn` throws `std::bad_function_call` (like `std::function`). -3. **Buffer Configuration**: `fn`/`unique_fn`/`safe_fn` support configurable buffer sizes (aligned), while `fn_ref` uses a fixed buffer (unused template param). +3. **Buffer Configuration**: `fn`/`unique_fn`/`classic_fn` support configurable buffer sizes (aligned), while `fn_ref` uses a fixed buffer (unused template param). 4. **Triviality**: `fn_ref` is trivially copyable (same as `std::function_ref`). @@ -157,11 +157,11 @@ auto main() -> int { - `Yes-R`: Convertible and non-owning wrapping. - `No`: Inconvertible -| From \ To | `ebd::fn` | `ebd::unique_fn` | `ebd::safe_fn` | `ebd::fn_ref` | +| From \ To | `ebd::fn` | `ebd::unique_fn` | `ebd::classic_fn` | `ebd::fn_ref` | | :---: | :---: | :---: | :---: | :---: | -| `ebd::fn` | Yes-D | Yes-D | No | Yes-R | +| `ebd::fn` | Yes-D | Yes-D | Yes-I | Yes-R | | `ebd::unique_fn` | No | Yes-D | No | Yes-R | -| `ebd::safe_fn` | Yes-I | Yes-I | Yes-D | Yes-R | +| `ebd::classic_fn` | Yes-I | Yes-I | Yes-D | Yes-R | | `ebd::fn_ref` | Yes-I | Yes-I | Yes-I | Yes-D | ## 🧩 Automatic deduction @@ -202,7 +202,7 @@ auto f = ebd::make_fn(Ambiguous_Callable_Object); // The Callable_Object should be unambiguously callable (non-overload) if `Signature` is omitted. auto f = ebd::make_fn(Callable_Object); auto f = ebd::make_fn(Callable_Object); -auto f = ebd::make_fn(Callable_Object); +auto f = ebd::make_fn(Callable_Object); auto f = ebd::make_fn(Callable_Object); ``` @@ -216,7 +216,7 @@ auto f = ebd::make_fn(std::in_place_type, {/*std::initializer_list*/}, ### Brief introduction -In embedded MCU development, it is often necessary to pass a C-style free function pointer as an argument, as existing libraries are typically written in C. To address this, we have implemented an `operator*` overload that simplifies converting an object of type `ebd::fn` / `ebd::unique_fn` / `ebd::safe_fn` / `ebd::fn_ref` to a C-style free function pointer. +In embedded MCU development, it is often necessary to pass a C-style free function pointer as an argument, as existing libraries are typically written in C. To address this, we have implemented an `operator*` overload that simplifies converting an object of type `ebd::fn` / `ebd::unique_fn` / `ebd::classic_fn` / `ebd::fn_ref` to a C-style free function pointer. If the object encapsulated by the function wrapper is a valid function pointer, this mechanism returns the pointer; otherwise, it returns nullptr. Basically, it is equivalent to a highly restricted `target()` method. @@ -262,7 +262,7 @@ export namespace ebd { using ::ebd::basic_fn; using ::ebd::fn; using ::ebd::unique_fn; - using ::ebd::safe_fn; + using ::ebd::classic_fn; using ::ebd::fn_ref; using ::ebd::make_fn; } @@ -276,7 +276,7 @@ import ebd.function; auto main() -> int { ebd::fn fn1 = []() { /* ... */ }; ebd::unique_fn fn2 = []() { /* ... */ }; - ebd::safe_fn fn3 = []() { /* ... */ }; + ebd::classic_fn fn3 = []() { /* ... */ }; ebd::fn_ref fn4 = fn2; auto fn5 = ebd::make_fn([]() { /* ... */ }); @@ -301,11 +301,11 @@ Go to the `/test/` directory, and follow the instructions in [`test/README ### Branch elimination -`ebd::fn` / `ebd::unique_fn` / `ebd::safe_fn` / `ebd::fn_ref` completely eliminate runtime checks for empty function states during invocation, significantly boosting performance of frequent function calls. +`ebd::fn` / `ebd::unique_fn` / `ebd::classic_fn` / `ebd::fn_ref` completely eliminate runtime checks for empty function states during invocation, significantly boosting performance of frequent function calls. ### Smart forwarding -`ebd::fn` / `ebd::unique_fn` / `ebd::safe_fn` / `ebd::fn_ref` enable scalar arguments and small-sized trivial arguments to be passed via registers instead of having to be passed via the stack as in `std::function`. This significantly reduces the memory access overhead during parameter passing. +`ebd::fn` / `ebd::unique_fn` / `ebd::classic_fn` / `ebd::fn_ref` enable scalar arguments and small-sized trivial arguments to be passed via registers instead of having to be passed via the stack as in `std::function`. This significantly reduces the memory access overhead during parameter passing. ### Zero-stack overhead @@ -313,7 +313,7 @@ Go to the `/test/` directory, and follow the instructions in [`test/README ### Stateless elimination -`ebd::fn` / `ebd::unique_fn` / `ebd::safe_fn` / `ebd::fn_ref` do not store the functor or its pointer if the functor is stateless (e.g., empty classes with trivial operations). This reduces memory access operations and improves cache efficiency. +`ebd::fn` / `ebd::unique_fn` / `ebd::classic_fn` / `ebd::fn_ref` do not store the functor or its pointer if the functor is stateless (e.g., empty classes with trivial operations). This reduces memory access operations and improves cache efficiency. > Click [x64-asm](./docs/perf/x86_64_msvc_asm_analysis.md), [rv32-asm](./docs/perf/riscv_gcc_asm_analysis.md) and [arm32-asm](./docs/perf/arm_gcc_asm_analysis.md) to see more details. diff --git a/docs/api/basic_fn.md b/docs/api/basic_fn.md index 9150da9..476da93 100644 --- a/docs/api/basic_fn.md +++ b/docs/api/basic_fn.md @@ -68,7 +68,7 @@ view(42); ## Notes -- Prefer using the predefined aliases (`ebd::fn`, `ebd::unique_fn`, `ebd::safe_fn`, `ebd::fn_view`) unless you need a combination not covered by them. +- Prefer using the predefined aliases (`ebd::fn`, `ebd::unique_fn`, `ebd::classic_fn`, `ebd::fn_ref`) unless you need a combination not covered by them. - The buffer size is automatically aligned to the nearest alignment boundary. - If the callable object is too large for the specified buffer size, a `static_assert` will be triggered at compile time. @@ -77,5 +77,5 @@ view(42); - [`ebd::detail::function`](./detail/function.md) - The underlying implementation - [`ebd::fn`](./fn.md) - For copyable callables - [`ebd::unique_fn`](./unique_fn.md) - For move-only callables -- [`ebd::safe_fn`](./safe_fn.md) - For exception-safe callables +- [`ebd::classic_fn`](./classic_fn.md) - For callables with `std::bad_function_call` on empty - [`ebd::fn_ref`](./fn_ref.md) - For non-owning views of callables \ No newline at end of file diff --git a/docs/api/classic_fn.md b/docs/api/classic_fn.md new file mode 100644 index 0000000..a343416 --- /dev/null +++ b/docs/api/classic_fn.md @@ -0,0 +1,73 @@ +# `ebd::classic_fn` + +## Overview + +`ebd::classic_fn` is a function object wrapper for copyable and callable objects. It is an alias of `ebd::detail::function` with specific configuration parameters that match the traditional `std::function` behavior: calling an empty wrapper throws `std::bad_function_call`. (if exceptions are enabled) + +## Template Parameters + +| Parameter | Description | +|-----------|-------------| +| `Signature` | Function signature, e.g., `Ret(Args...)` or `Ret(Args...) const`. | +| `BufferSize` | Buffer size used for storing the callable object. Defaults to `detail::default_buffer_size::value` if omitted. | + +## Configuration + +`ebd::classic_fn` is configured with the following parameters: + +| Configuration | Value | Description | +|---------------|-------|-------------| +| `IsCopyable` | `true` | The callable object must be copyable. | +| `IsView` | `false` | This is not a view; the wrapper owns the callable object. | +| `IsThrowing` | `true` | The wrapper will throw `std::bad_function_call` when called in an empty state. | +| `AssertObjectNoThrow` | `false` | The callable object does not need to be nothrow-constructible or nothrow-destructible. | + +## Member Functions + +All member functions of `ebd::detail::function` are available for `ebd::classic_fn`. For detailed documentation, see [`ebd::detail::function`](./detail/function.md). + +## Usage Examples + +### Basic Usage + +```cpp +#include "embed/embed_function.hpp" + +// Create a classic function wrapper for a void(int) signature +ebd::classic_fn fn; + +// Assign a function pointer +void foo(int x) { /* do something */ } +fn = &foo; +fn(42); + +// Assign a lambda +fn = [](int x) { /* do something */ }; +fn(42); +``` + +### With Custom Buffer Size + +```cpp +// Create a classic function wrapper with a custom buffer size +ebd::classic_fn fn; // 32-byte buffer + +// Assign a larger lambda with captures +int value = 42; +fn = [value](int x) { /* use value */ }; +fn(100); +``` + +## Notes + +- `ebd::classic_fn` is copyable and owns the callable object it wraps. +- The buffer size is automatically aligned to the nearest alignment boundary. +- If the callable object is too large for the specified buffer size, a `static_assert` will be triggered at compile time. +- When called in an empty state, `ebd::classic_fn` will throw `std::bad_function_call` (if exceptions are enabled), matching `std::function` behavior. + +## See Also + +- [`ebd::detail::function`](./detail/function.md) - The underlying implementation +- [`ebd::fn`](./fn.md) - For copyable callables (terminate on empty) +- [`ebd::unique_fn`](./unique_fn.md) - For move-only callables +- [`ebd::fn_ref`](./fn_ref.md) - For non-owning views of callables diff --git a/docs/api/detail/function.md b/docs/api/detail/function.md index 4bf5667..a60cc2f 100644 --- a/docs/api/detail/function.md +++ b/docs/api/detail/function.md @@ -276,7 +276,7 @@ int result = add(10, 20); // result = 30 ## Notes -- The `ebd::detail::function` class is not intended for direct use. Instead, use the predefined aliases such as `ebd::fn`, `ebd::unique_fn`, `ebd::safe_fn`, and `ebd::fn_view`. +- The `ebd::detail::function` class is not intended for direct use. Instead, use the predefined aliases such as `ebd::fn`, `ebd::unique_fn`, `ebd::classic_fn`, and `ebd::fn_ref`. - The buffer size is automatically aligned to the nearest alignment boundary. - The function wrapper supports all callable objects, including free functions, lambdas, functors, static member functions, and member functions. - When `Config::isView` is `true`, the wrapper acts as a non-owning view, similar to `std::function_ref`. \ No newline at end of file diff --git a/docs/api/fn.md b/docs/api/fn.md index 1a84206..519a0a5 100644 --- a/docs/api/fn.md +++ b/docs/api/fn.md @@ -19,7 +19,7 @@ |---------------|-------|-------------| | `IsCopyable` | `true` | The callable object must be copyable. | | `IsView` | `false` | This is not a view; the wrapper owns the callable object. | -| `IsThrowing` | `true` | The wrapper will throw `std::bad_function_call` when called in an empty state. | +| `IsThrowing` | `false` | The wrapper will call `std::terminate()` when called in an empty state. | | `AssertObjectNoThrow` | `false` | The callable object does not need to be nothrow-constructible or nothrow-destructible. | ## Member Functions @@ -70,11 +70,11 @@ fn(100); - `ebd::fn` is copyable and owns the callable object it wraps. - The buffer size is automatically aligned to the nearest alignment boundary. - If the callable object is too large for the specified buffer size, a `static_assert` will be triggered at compile time. -- When called in an empty state, `ebd::fn` will throw `std::bad_function_call` (if exceptions are enabled). +- When called in an empty state, `ebd::fn` will call `std::terminate()`. ## See Also - [`ebd::detail::function`](./detail/function.md) - The underlying implementation - [`ebd::unique_fn`](./unique_fn.md) - For move-only callables -- [`ebd::safe_fn`](./safe_fn.md) - For exception-safe callables +- [`ebd::classic_fn`](./classic_fn.md) - For callables with `std::bad_function_call` on empty - [`ebd::fn_ref`](./fn_ref.md) - For non-owning views of callables \ No newline at end of file diff --git a/docs/api/fn_ref.md b/docs/api/fn_ref.md index 3f5ddc1..2fda15f 100644 --- a/docs/api/fn_ref.md +++ b/docs/api/fn_ref.md @@ -125,4 +125,4 @@ process_data(100, &handle_result); - [`ebd::detail::function`](./detail/function.md) - The underlying implementation - [`ebd::fn`](./fn.md) - For copyable callables - [`ebd::unique_fn`](./unique_fn.md) - For move-only callables -- [`ebd::safe_fn`](./safe_fn.md) - For exception-safe callables +- [`ebd::classic_fn`](./classic_fn.md) - For callables with `std::bad_function_call` on empty diff --git a/docs/api/make_fn.md b/docs/api/make_fn.md index 32d9796..8787fb5 100644 --- a/docs/api/make_fn.md +++ b/docs/api/make_fn.md @@ -9,7 +9,7 @@ It can: - deduce the signature of a lambda or other uniquely callable functor, - choose `ebd::fn` or `ebd::unique_fn` automatically, - build an empty wrapper with an explicit signature, -- create a wrapper with a specific wrapper type such as `ebd::safe_fn` or `ebd::fn_ref`. +- create a wrapper with a specific wrapper type such as `ebd::classic_fn` or `ebd::fn_ref`. ## Overloads @@ -18,16 +18,12 @@ It can: ```cpp template , - std::size_t BufferSize = sizeof(Class), - typename Fn = detail::conditional_t< - std::is_copy_constructible::value, - fn, - unique_fn>, bool NoThrow = detail::is_nothrow_construct_from_functor::value> -EMBED_NODISCARD inline Fn make_fn(Functor&& functor) noexcept(NoThrow); +EMBED_NODISCARD inline fn +make_fn(Functor&& functor) noexcept(NoThrow); ``` -Creates a wrapper for a class-type callable when the signature is specified explicitly. For copyable functors, the resulting type is `ebd::fn`. +Creates an `ebd::fn` for a class-type callable when the signature is specified explicitly. The buffer size is automatically deduced as `sizeof(Class)`. ### 2. Move-only functor with explicit signature @@ -61,11 +57,21 @@ make_fn(Ret (*func_ptr)(Args...)) noexcept; Creates an `ebd::fn` from a free-function pointer and deduces both signature and buffer size. +### 4b. noexcept function pointer with deduced signature (C++17+) + +```cpp +template +EMBED_NODISCARD inline fn +make_fn(Ret (*func_ptr)(Args...) noexcept) noexcept; +``` + +Creates an `ebd::fn` from a noexcept free-function pointer. The noexcept qualifier is preserved in the signature. Only available when noexcept is part of the type system (C++17 or `__cpp_noexcept_function_type >= 201510L`). + ### 5. Function pointer with explicit signature ```cpp template ::pure_sig*> + typename FunctionPtr = typename detail::unwrap_signature::pure_sig_noex*> EMBED_NODISCARD inline fn make_fn(FunctionPtr func_ptr) noexcept; ``` @@ -118,7 +124,7 @@ template EMBED_NODISCARD inline auto make_fn(Ret(Class::* memfunc)(Args...) C V REF NOEXCEPT) noexcept -> fn< - Ret(detail::get_qualified_with_t, Args...) const, + Ret(detail::get_qualified_with_t, Args...) const NOEXCEPT, sizeof(memfunc) >; ``` @@ -143,10 +149,11 @@ Creates an `ebd::fn` from a pointer to member function using the specified signa template ::type> EMBED_NODISCARD inline auto make_fn(T Class::* ptr_memobj) noexcept --> fn; +-> fn::value), + sizeof(ptr_memobj)>; ``` -Creates an `ebd::fn` that reads a member object from an instance. +Creates an `ebd::fn` that reads a member object from an instance. The noexcept qualifier is deduced from the member access expression. ### 12. In-place construction (C++17+) @@ -174,7 +181,7 @@ template