Provides improved implementations of std::function
:
fu2::function
fu2::unique_function
(capable of holding move only types)fu2::function_view
(capable of referencing callables in a non owning way)that provide many benefits and improvements over std::function
:
operator()
signature)std::function
as well as other callable typesfu2::function_base
(internal capacity, copyable and exception guarantees)fu2::function<bool(int), bool(float)>
)std::function
, which doesn't provide support anymorefunction.hpp
in your projectfunction2 is implemented in one header (function.hpp
), no compilation is required.
Just copy the function.hpp
header in your project and include it to start.
It's recommended to import the library as git submodule using CMake:
# Shell:
git submodule add https://github.com/Naios/function2.git
# CMake file:
add_subdirectory(function2)
# function2 provides an interface target which makes it's
# headers available to all projects using function2
target_link_libraries(my_project function2)
Use fu2::function
as a wrapper for copyable function wrappers and fu2::unique_function
for move only types.
The standard implementation std::function
and fu2::function
are convertible to each other, see the chapter convertibility of functions for details.
A function wrapper is declared as following:
fu2::function<void(int, float) const>
// Return type ~^ ^ ^ ^
// Parameters ~~~~~|~~~~~| ^
// Qualifier ~~~~~~~~~~~~~~~~~~~|
ReturnType operator() (Args...)
ReturnType operator() (Args...) const
ReturnType operator() (Args...) volatile
ReturnType operator() (Args...) const volatile
ReturnType operator() (Args...) &&
const
, volatile
and noexcept
). Can only wrap callable objects which call operator is also qualified as &&
(r-value callable). Normal (C) functions are considered to be r-value callable by default.ReturnType operator() (Args...) noexcept
const
, volatile
and &&
). Can only wrap functions or callable objects which call operator is also qualified as noexcept
. Requires enabled C++17 compilation to work (support is detected automatically). Empty function calls to such a wrapped function will lead to a call to std::abort
regardless the wrapper is configured to support exceptions or not (see adapt function2).fu2::function<int(std::vector<int> const&),
int(std::set<int> const&) const> fn = [] (auto const& container) {
return container.size());
};
fu2::function
and fu2::unique_function
(non copyable) are easy to use:
fu2::function<void() const> fun = [] {
// ...
};
// fun provides void operator()() const now
fun();
fu2::unique_function
also works with non copyable functors/ lambdas.
fu2::unique_function<bool() const> fun = [ptr = std::make_unique<bool>(true)] {
return *ptr;
};
// unique functions are move only
fu2::unique_function<bool() const> otherfun = std::move(fun):
otherfun();
A fu2::function_view
can be used to create a non owning view on a persistent object. Note that the view is only valid as long as the object lives.
auto callable = [ptr = std::make_unique<bool>(true)] {
return *ptr;
};
fu2::function_view<bool() const> view(callable);
fu2::function
, fu2::unique_function
and std::function
are convertible to each other when:
noconst = const
const = const
noconst = noconst
unique = unique
unique = copyable
copyable = copyable
lvalue = lvalue
lvalue = rvalue
rvalue = rvalue
noexcept
correct when:
callable = callable
callable = noexcept callable
noexcept callable = noexcept callable
Convertibility from \ to | fu2::function | fu2::unique_function | std::function |
---|---|---|---|
fu2::function | Yes | Yes | Yes |
fu2::unique_function | No | Yes | No |
std::function | Yes | Yes | Yes |
fu2::function<void()> fun = []{};
// OK
std::function<void()> std_fun = fun;
// OK
fu2::unique_function<void()> un_fun = fun;
// Error (non copyable -> copyable)
fun = un_fun;
// Error (non copyable -> copyable)
fun = un_fun;
function2 is adaptable through fu2::function_base
which allows you to set:
struct my_capacity {
static constexpr std::size_t capacity = sizeof(my_type);
static constexpr std::size_t alignment = alignof(my_type);
};
fu2::bad_function_call
exception, otherwise std::abort
is called.The following code defines an owning function with a variadic signature which is copyable and sfo optimization is disabled:
template<typename Signature>
using my_function = fu2::function_base<true, true, fu2::capacity_none, true, false, Signature>;
The following code defines a non copyable function which just takes 1 argument, and has a huge capacity for internal sfo optimization. Also it must be called as r-value.
template<typename Arg>
using my_consumer = fu2::function_base<true, false, fu2::capacity_fixed<100U>,
true, false, void(Arg)&&>;
// Example
my_consumer<int, float> consumer = [](int, float) { }
std::move(consumer)(44, 1.7363f);
function2 uses small functor optimization like the most common std::function
implementations which means it allocates a small internal capacity to evade heap allocation for small functors.
Smart heap allocation moves the inplace allocated functor automatically to the heap to speed up moving between objects.
It's possible to disable small functor optimization through setting the internal capacity to 0.
Function2 is checked with unit tests and valgrind (for memory leaks), where the unit tests provide coverage for all possible template parameter assignments.
Tested with:
Every compiler with modern C++14 support should work. function2 only depends on the standard library.
function2 is licensed under the very permissive Boost 1.0 License.
There are similar implementations of a function wrapper:
Also check out the amazing CxxFunctionBenchmark which compares several implementations.