An open API service indexing awesome lists of open source software.

https://github.com/avakar/small_function

Allocation-free move-only alternative to std::function for C++17
https://github.com/avakar/small_function

Last synced: about 2 months ago
JSON representation

Allocation-free move-only alternative to std::function for C++17

Awesome Lists containing this project

README

        

# small_function

Allocation-free move-only alternative to `std::function` for C++17.

## Getting Started

The library is header-only. To use it, clone the repo somewhere
and add the `include` directory to your include path.

If you're using CMake, use the FetchContent module.

```cmake
FetchContent_Declare(
avakar.small_function
GIT_REPOSITORY https://github.com/avakar/small_function.git
GIT_TAG main
GIT_SHALLOW 1
)
FetchContent_MakeAvailable(avakar.small_function)

target_link_libraries(my_target PUBLIC avakar::small_function)
```

## Usage

Include `` and you're good to go.

```cpp
#include
using avakar::small_function;

void get_answer(small_function fn)
{
if (fn)
fn(42);
}

int main()
{
get_answer([](int x) {
// ...
});
}
```

You mustn't invoke `small_function` while it's empty. Default
constructor will construct an empty object. The object
contextually converts to bool indicating whether it's non-empty.

By default, `small_function` objects are large enough to contain
a function pointer or a lambda with at most one captured pointer.

```cpp
small_function a = [this] {}; // ok, only one capture
small_function b = [this, x] {}; // error, lambda too large
small_function c = &abort; // ok, plain function pointer
```

You can adjust the size and alignment of the internal storage.

```cpp
my_overaligned_type o; // assume sizeof(o) == 32, alignof(o) == 16
small_function a = [o]{}; // error, lambda too large
small_function b = [o]{}; // error, after alignment the lambda is too large
small_function c = [o]{}; // ok
small_function d = [o]{}; // ok, even after alignment the lambda will fit
```

Zero-sized storage is allowed. Non-capturing lambdas
will fit in those, but function pointers won't.

```cpp
small_function a = []{}; // ok, zero-sized lambda
small_function b = [this]{}; // error, lambda too large
small_function c = &abort; // error, function pointer too large
```

Template parameters can be deduced automatically from an initializer.

```cpp
small_function a = [] { return 42; };
// decltype(a) == small_function

small_function b = [this] { return 42; };
// decltype(b) == small_function
```

The function type can include `noexcept`.

```cpp
small_function a = []{}; // error, lambda is not noexcept
small_function b = []() noexcept {}; // ok
small_function c = std::move(b); // ok
small_function d = std::move(c); // error, weakening exception specification
```

## Reference

```cpp
template
struct small_function
{
// Creates the `small_function` object with an empty state.
// Such object will be falsy and its `operator()` must not be invoked.
small_function() noexcept;

// Creates the `small_function` object containing `f`.
// This constructor only contributes to the overload set if
//
// * `f` fits in the storage (see below),
// * `f(an...)` is convertible to `R`, and
// * either `noexcept(f(an...))` or `!ne`.
//
// The resulting object will be truthy.
template
small_function(F f) noexcept;

// Indicates whether the object is non-empty.
explicit operator bool() const noexcept;

// Invokes the contained function object.
// Behavior is undefined if `this` is empty.
R operator()(An &&... an) noexcept(ne)

small_function(small_function && o) noexcept;
small_function & operator=(small_function o) noexcept;
};
```

An object fits in a storage if the size of the storage is sufficient for
both the object and the maximum padding for alignment. The object might
have to be padded by as many as `alignof(obj) - alignof(storage)` bytes.