GithubHelp home page GithubHelp logo

naios / function2 Goto Github PK

View Code? Open in Web Editor NEW
536.0 13.0 47.0 549 KB

Improved and configurable drop-in replacement to std::function that supports move only types, multiple overloads and more

Home Page: http://naios.github.io/function2

License: Boost Software License 1.0

C++ 91.11% CMake 6.84% Shell 1.39% Python 0.65%
function functional function-wrapper type-erasure

function2's Introduction

fu2::function an improved drop-in replacement to std::function

Build Status Build status

Provides improved implementations of std::function:

  • copyable fu2::function
  • move-only fu2::unique_function (capable of holding move only types)
  • non-owning fu2::function_view (capable of referencing callables in a non owning way)

that provide many benefits and improvements over std::function:

  • const, volatile, reference and noexcept correct (qualifiers are part of the operator() signature)
  • convertible to and from std::function as well as other callable types
  • adaptable through fu2::function_base (internal capacity, copyable and exception guarantees)
  • overloadable with an arbitrary count of signatures (fu2::function<bool(int), bool(float)>)
  • full allocator support in contrast to std::function, which doesn't provide support anymore
  • covered by many unit tests and continuous integration services (GCC, Clang and MSVC)
  • header only, just copy and include function.hpp in your project
  • permissively licensed under the boost license

Table of Contents

Documentation

How to use

function2 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 ~~~~~~~~~~~~~~~~~~~|
  • Return type: The return type of the function to wrap.
  • Arguments: The argument types of the function to wrap. Any argument types are allowed.
  • Qualifiers: There are several qualifiers allowed:
    • no qualifier provides ReturnType operator() (Args...)
      • Can be assigned from const and no const objects (mutable lambdas for example).
    • const provides ReturnType operator() (Args...) const
      • Requires that the assigned functor is const callable (won't work with mutable lambdas),
    • volatile provides ReturnType operator() (Args...) volatile
      • Can only be assigned from volatile qualified functors.
    • const volatile provides ReturnType operator() (Args...) const volatile
      • Same as const and volatile together.
    • r-value (one-shot) functions ReturnType operator() (Args...) &&
      • one-shot functions which are invalidated after the first call (can be mixed with 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.
    • noexcept functions ReturnType operator() (Args...) noexcept
      • such functions are guaranteed not to throw an exception (can be mixed with 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).
  • Multiple overloads: The library is capable of providing multiple overloads:
    fu2::function<int(std::vector<int> const&),
                  int(std::set<int> const&) const> fn = [] (auto const& container) {
                    return container.size());
                  };

Constructing a function

fu2::function and fu2::unique_function (non copyable) are easy to use:

fu2::function<void() const> fun = [] {
  // ...
};

// fun provides void operator()() const now
fun();

Non copyable unique functions

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();

Non owning functions

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);

Convertibility of functions

fu2::function, fu2::unique_function and std::function are convertible to each other when:

  • The return type and parameter type match.
  • The functions are both volatile or not.
  • The functions are const correct:
    • noconst = const
    • const = const
    • noconst = noconst
  • The functions are copyable correct when:
    • unique = unique
    • unique = copyable
    • copyable = copyable
  • The functions are reference correct when:
    • lvalue = lvalue
    • lvalue = rvalue
    • rvalue = rvalue
  • The functions are 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;

Adapt function2

function2 is adaptable through fu2::function_base which allows you to set:

  • IsOwning: defines whether the function owns its contained object
  • Copyable: defines if the function is copyable or not.
  • Capacity: defines the internal capacity used for sfo optimization:
struct my_capacity {
  static constexpr std::size_t capacity = sizeof(my_type);
  static constexpr std::size_t alignment = alignof(my_type);
};
  • IsThrowing defines if empty function calls throw an fu2::bad_function_call exception, otherwise std::abort is called.
  • HasStrongExceptGuarantee defines whether the strong exception guarantees shall be met.
  • Signatures: defines the signatures of the function.

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);

Performance and optimization

Small functor optimization

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.

Coverage and runtime checks

Function2 is checked with unit tests and valgrind (for memory leaks), where the unit tests provide coverage for all possible template parameter assignments.

Compatibility

Tested with:

  • Visual Studio 2017+ Update 3
  • Clang 3.8+
  • GCC 5.4+

Every compiler with modern C++14 support should work. function2 only depends on the standard library.

License

function2 is licensed under the very permissive Boost 1.0 License.

Similar implementations

There are similar implementations of a function wrapper:

Also check out the amazing CxxFunctionBenchmark which compares several implementations.

function2's People

Contributors

dowens-pp avatar feverzsj avatar frankhb avatar gjasny avatar hikarin522 avatar klaim avatar madmongo1 avatar maierlars avatar mbkkt avatar mystor avatar naios avatar wak-google avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

function2's Issues

Please release a v4 patch release

Hello,

could you please release a new version which includes the MSVC 16.3 fix (#29)? I'm adding function2 to Microsoft vcpkg here and would like to use a proper version.

Thanks,
Gregor

Compile time bug with noexcept specifier

@Naios

Cannot use noexcept specifier.
Looks like a compile time bug. I think something should be sfinae but its not


Commit Hash

last, 035bec2

Expected Behavior

Should compile

Actual Behavior

Don't compile

Steps to Reproduce

See godbolt

Your Environment

  • OS: Arch Linux
  • Compiler and version: gcc 12.1

Cannot compile with Clang with exceptions turned off

I would like to use a self-defined version of unique_function using function_base which doesn't throw an exception, as I would prefer to use Clang's default setting of no exceptions. However, as soon as I include the header file, Clang parses it and complains that throw() isn't supported.

Adding the -fdelayed-template-parsing flag to Clang works, however if possible I would rather not use WIP (and non-standard, according to this answer) flags.

Is it possible to modify the header file so that it only exposes exception code if exceptions are turned on?

ToDo: Roadmap

  • Custom allocator support
  • std::function interface backward compatibility

Won't compile with Visual Studio 2019 16.3, 16.2 works good.

@Naios

Error in VS 16.3:

error C2440: 'static_cast': cannot convert from 'fu2::abi_400::detail::type_erasure::erasure<true,Config,fu2::abi_400::detail::property<true,false,void *(void *)>>' to 'erasure_t &'
error C2440: with
error C2440: [
error C2440: Config=fu2::abi_400::detail::config<true,false,fu2::capacity_default>
error C2440: ]

Commit Hash

5dcbecd

Expected Behavior

Should compile

Actual Behavior

Won't compile

Steps to Reproduce

Try and compile uwebsockets with Visual Studio 2019 16.3
I also created an issue here:
uNetworking/uWebSockets#940
However I think the issue only is in the function2 lib.

Your Environment

Windows 10, x64
Visual Studio 2019 16.3
MSVC V142

Got MSVC error C2248 when I use unique_function with boost::callable_traits::is_invocable

@Naios

When I use fu2::unique_function with boost::callable_traits::is_invocable on msvc v19.33 or older (on godbolt) , then I got C2248 error.
It doesn't happen with std::function.
When I test it on msvc latest (on godbolt), no error happens.
When I test it on g++ and clang++, no error happens.

It might be msvc issue, but msvc v19.33 is not so old. If fu2::unique_function could avoid the issue, it is very helpful.


Commit Hash

2d3a878

Expected Behavior

Build finished without the error.

Actual Behavior

Got C2248 (cannot access private member) error.

Steps to Reproduce

#include <function2/function2.hpp>
#include <boost/callable_traits.hpp>
#include <type_traits>

using std_func_t = std::function<void()>;
using unique_func_t = fu2::unique_function<void()>;


int main() {
    // std::function : no error
    static_assert(boost::callable_traits::is_invocable<std_func_t>::value);
    // fu2::unique_function : error C2248 on msvc v19.33 and older
    static_assert(boost::callable_traits::is_invocable<unique_func_t>::value);
}

Godbolt link

Compiler Link Result
msvc v19.33 https://godbolt.org/z/PxMa4q3oo error C2248
msvc latest https://godbolt.org/z/bbrxb6nTe no error
clang++ 15.0.0 https://godbolt.org/z/zPEGqbjsn no error
g++ 12.2 https://godbolt.org/z/7Eb1hs8KW no error

Your Environment

  • OS: Windows
  • Compiler and version: MSVC v19.33 (godbolt)

Any docs about the custom allocator?

Hi! I saw in the readme that custom Allocator is already supported. However, the usage of this in the source code is quite complex. Is there a more intuitive example of how to use it?
Additionally, as hardware updates quickly, are there any new benchmark data available?

Thank you!

Please create a new release

Hello,

thanks for maintaining this really useful library!

It's been a while since the last release. Could you please create a new one?

Thanks,
-Gregor

Wrong static_assert for function that should be a unique_function.

@Naios


Commit Hash

e3695b4

Expected Behavior

When trying to make a fu2::function with a move-only object, you get an assert_error with the message "Can't wrap a non copyable object into a fu2::function, try using fu2::unique_function instead."

Actual Behavior

You get an error with "Can't wrap a non copyable object into a unique function!", which is super confusing.

Code at https://github.com/Naios/function2/blob/master/include/function2/function2.hpp#L1262

Compiling as Objective-C++ conflict due to block pointer conversion

@Naios


Commit Hash

7cd9537

Expected Behavior

Compilation works as expected

Actual Behavior

Compilation fails with the following error:

.../function2.hpp:1131:14: Call to implicitly-deleted copy constructor of 'const (lambda at .../main.mm:27:25)'

Implicit capture of lambda object due to conversion to block pointer here (1131:14, if (bool(callable)) {)

Steps to Reproduce

Compile the following in Xcode as a .mm file:

#include <memory>
#include "function2.hpp"

template<typename Signature>
using r_function = fu2::function_base<
	true,
	false,
	fu2::capacity_default,
	false,
	false,
	Signature
>;

int main(int argc, const char * argv[])
{
	std::unique_ptr<int> testInt = std::make_unique<int>(4);
	int r_testInt = 0;
	
	auto parameterUpdate = [&, testInt = std::move(testInt)]()
	{
		if (testInt)
		{
			r_testInt = *testInt;
		}
	};
	
	r_function<void()> myFunc(std::move(parameterUpdate));
	//fu2::unique_function<void()> myFunc(std::move(parameterUpdate)); //This fails too
	
	return 0;
}

Your Environment

  • OS: OSX
  • Compiler and version: Xcode 11.2.1, Apple Clang, compiled as C++17
  • Standard library (if non default): libc++

Constructing function_view from fu2::function

@Naios


As a workaround for issue #12 I tried to use fu2::function_view instead of a const-ref to a fu2::unique_function. Implicit conversion doesn't work here (it does for std::function).
Is this intentional?

Sample code (doesn't compile with GCC/Clang):

#include <function2/function2.hpp>
#include <iostream>

static void call(fu2::function_view<void()> fun)
{
   fun();
}

int main()
{
   fu2::unique_function<void()> fun = [] { std::cout << "Hello World\n"; };
   call(fun);
   return 0;
}

The error from Clang looks helpful:

$ clang-6.0 -std=c++17 -o fu2_view fu2_view.cpp -I function2-3.0.0/include/
fu2_view.cpp:12:4: error: no matching function for call to 'call'
   call(fun);
   ^~~~
fu2_view.cpp:4:13: note: candidate function not viable: no known conversion from 'function_base<true, false, [4 * ...]>' to
      'function_base<false, true, [4 * ...]>' for 1st argument
static void call(fu2::function_view<void()> fun)
            ^
1 error generated.

Please add an analogue of emplace

@Naios

Being able to construct an object rather than having to copy/move one in would be very useful, particularly for objects that may be expensive to construct, or (for unique_function) immovable objects. (After all, if they're on the heap we can still move the pointer.)


Commit Hash

7cd9537

Expected Behavior

Being able to type something like
fun.emplace<Foo>(something, something)

Actual Behavior

Needing to type fun = Foo(something, something)

Steps to Reproduce

N/A

Your Environment

  • OS: Fedora 30
  • Compiler and version: GCC 9.2.1
  • Standard library (if non default): libstdc++-9.2.1

Cannot call const-ref to function

@Naios


Expected Behavior

Taking functions by const-ref and calling them should be possible (same as std::function).

Actual Behavior

Calling a const-ref fu2::function fails to compile (same for unique_function and function_view). Output from GCC:

error: no match for call to ‘(fu2::function<void()> {aka const fu2::abi_300::detail::function<fu2::abi_300::detail::config<true, true, 16ul>, fu2::abi_300::detail::property<true, false, void()> >}) ()’
    fun();
        ^
In file included from fu2_constref.cpp:1:0:
function2-3.0.0/include/function2/function2.hpp:595:9: note: candidate: Ret fu2::abi_300::detail::type_erasure::invocation_table::operator_impl<Index, fu2::abi_300::detail::function<Config, Property>, Ret(Args ...)>::operator()(Args ...) [with long unsigned int Index = 0ul; Config = fu2::abi_300::detail::config<true, true, 16ul>; Property = fu2::abi_300::detail::property<true, false, void()>; Ret = void; Args = {}] <near match>
     Ret operator()(Args... args) CONST VOLATILE OVL_REF {                      \

Steps to Reproduce

Sample code:

#include <function2/function2.hpp>
#include <iostream>

static void call(const fu2::function<void()>& fun)
{
   fun();
}

int main()
{
   fu2::function<void()> fun = [] { std::cout << "Hello World\n"; };
   call(fun);
   return 0;
}

Your Environment

  • OS: Linux
  • Compiler and version: tested with GCC 5.4 & 6.3, Clang 4/5/6
    Tested with 2.3.0, 3.0.0 and current master.

Some compiler warnings are generated

@Naios

This is relatively minor, but I thought I'd mention it before I forget about them: building function2 strictly as a copied header with clang can trigger a few warnings, if you enable them.


Commit Hash

5b8e6de

Expected Behavior

Builds cleanly (no warnings).

Actual Behavior

Building generates warnings, as follows:

  1. An uninitialized-member warning due to member variables cmd_ and vtable_ not having default initializers and not being explicitly initialized in the default constructor for class type_erasure::tables::vtable.
member 'cmd_' is missing from constructor initializer list [-Werror,-Wuninitialized-member]
member 'vtable_' is missing from constructor initializer list [-Werror,-Wuninitialized-member]

Easily fixed by changing the member declarations this:

    command_function_t cmd_{nullptr};
    typename invoke_table_t::type vtable_{nullptr};
  1. The use of the variable name allocator in various places triggers a shadow warning, due to the base class in libstdc++ also using it. (note: this is a gcc warning and was built with gcc, not clang)
declaration of 'allocator' shadows a member of ... [-Werror=shadow]
include/c++/7/bits/allocator.h:109:5: note: shadowed declaration is here
  1. The enum class opcode enumerations use doxygen-like comments that don't follow doxygen correctly, triggering a documentation warning.
not a Doxygen trailing comment [-Werror,-Wdocumentation]
     op_move,         //< Move the object and set the vtable
                      ^~~
                      ///<

Changing them to this fixes it:

enum class opcode
{
    op_move,         ///< Move the object and set the vtable
    op_copy,         ///< Copy the object and set the vtable
    op_destroy,      ///< Destroy the object and reset the vtable
    op_weak_destroy, ///< Destroy the object without resetting the vtable
    op_fetch_empty,  ///< Stores true or false into the to storage
                     ///< to indicate emptiness
};

Steps to Reproduce

Build using clang with -Weverything or the specific warnings described earlier, except for (2) which was found using gcc.

This was built simply as a copied header - i.e., not using the CMake settings in this project. (built for C++17)

Your Environment

  • OS: Linux
  • Compiler and version: clang version 5.0.0
  • Standard library (if non default): gcc's libstdc++ (from gcc version 7.3.1)

fu2::function_view created from empty fu2::function is not itself empty

@Naios

Instantiating an fu2::function_view from an empty fu2::function does not produce an empty fu2::function_view. I didn't look into it too deeply but my initial impression is that it's due to the constructor for arbitrary callables function(T&& callable) getting called instead of function(function<RightConfig, property_t> const& right) as I would expect, so the erasure_t is constructed to wrap the fu2::function as a whole instead of unpacking it.


Commit Hash

e3695b4

Steps to Reproduce

// empty_function_view_test.cpp
#include <catch2/catch.hpp>
#include <function2/function2.hpp>

#include <optional>
#include <string>

TEST_CASE("Function2 function -> function_view", "[function2]")
{
    fu2::function<std::optional<size_t>(const std::string&)> f = [](const std::string &str) -> std::optional<size_t> {
        if (str.size() > 0) { return str.size(); }
        else { return std::nullopt; }
    };
    REQUIRE_FALSE(f.empty()); // pass
    fu2::function_view<std::optional<size_t>(const std::string&)> fv = f;
    REQUIRE_FALSE(fv.empty()); // pass

    fu2::function<std::optional<size_t>(const std::string&)> emptyf{};
    REQUIRE(emptyf.empty()); // pass
    fu2::function_view<std::optional<size_t>(const std::string&)> emptyfv = emptyf;
    REQUIRE(emptyfv.empty()); // fail
}

Your Environment

  • OS: Mac OS Mojave, Gentoo Linux
  • Compiler and version: appleclang-10.0.1, gcc-8.3

-Waddress warning generated for non-capturing lambdas on gcc <= 9.2

@Naios

In gcc versions before 9.3, the compiler would generate a -Waddress warning complaining that the address of a lambda's function will never be null if it is cast to a boolean (compiler explorer), even in generic code.

This impacts function2 because the generic logic to determine if a newly-constructed function object should be empty ends up triggering these warnings when passed a captureless lambda in various places, as it passes the use_bool_op checks:

if (bool(callable)) {

if (bool(callable)) {

if (bool(callable)) {

This can be seen with this example compiler explorer instance hitting the warning from each of these places: https://godbolt.org/z/vvKfonTa1

I can't think of a practical way off the top of my head to detect non-nullable captureless lambdas in use_bool_op and treat them differently than other function-like objects which can convert to bool, so the easiest approach may be to suppress the warning on these older compiler versions. It appears that libstdc++ just manually enumerates all types which can be checked for emptyness as required by the spec (https://github.com/gcc-mirror/gcc/blob/3b3f2f7c265ef9f176cb811a8049b24538d954d9/libstdc++-v3/include/bits/std_function.h#L210-L228) which I imagine isn't a practical approach for this library.


Commit Hash

02ca998

Expected Behavior

No warning is emitted when building with -Waddress

Actual Behavior

-Waddress warnings are emitted on gcc 9.2 and earlier when constructing or assigning a function2 function object with a captureless lambda.

Steps to Reproduce

Use the function2 library with gcc 9.2 or earlier, enable -Waddress warnings, and construct a function2 function object with a captureless lambda.

Example godbolt instance: https://godbolt.org/z/vvKfonTa1

Your Environment

  • OS: Linux (Ubuntu LTS)
  • Compiler and version: GCC 9.2 and earlier
  • Standard library (if non default): libstdc++ (default)

Get pointer to target

@Naios

Great improvement over std::function, but there is no std::function::target counterpart. I use it for logging addresses of underlying callable objects, very useful for debugging:

...
catch (const std::exception &e)
{
    LOG_ERROR("Async function 0x%p raised exception: %s", f.target<void(*)(void)>(), e.what());
}

Any chance of implementing such feature?

Potential null pointer dereference in Function2

@Naios


Commit Hash

Function2 tags 4.2.0 and 4.2.1, hashes:
02ca998
f569a63

Expected Behavior

Test case pasted below compiles without errors with
g++-11 -O1 -Wnull-dereference -c -o null-deref.o null-deref.cpp

Actual Behavior

Test case given below produces a warning for a null pointer dereference:

g++-11 -O1 -Wnull-dereference   -c -o null-deref.o null-deref.cpp
null-deref.cpp: In static member function ‘static Ret fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args ...)>::internal_invoker<T, IsInplace>::invoke(fu2::abi_400::detail::type_erasure::data_accessor*, std::size_t, Args ...) [with T = fu2::abi_400::detail::type_erasure::box<false, Foo::bar()::<lambda()>, std::allocator<Foo::bar()::<lambda()> > >; bool IsInplace = true; Ret = int; Args = {}]’:
null-deref.cpp:14:44: warning: potential null pointer dereference [-Wnull-dereference]
   14 |     CallbackT c = std::move([=]() { return x; });
      |                                            ^
null-deref.cpp:14:44: warning: potential null pointer dereference [-Wnull-dereference]

Steps to Reproduce

Test case file:

//#include "function2.hpp"
#include "function2-upstream-master.hpp"
#include <functional>
#include <iostream>
//#include "function2.hpp-fixed"

using namespace std;

class Foo {
public:
  using CallbackT = fu2::unique_function<int(void)>;
  void bar(void) {
    int x = 10;
    CallbackT c = std::move([=]() { return x; });
  }
};

int main(void) {
  Foo a;
  a.bar();
  return 0;
}

Compile with the command:

g++-11 -O1 -Wnull-dereference   -c -o null-deref.o null-deref.cpp

This issue can be solved by the following patch to function2.hpp

Patch to tag 4.2.0
--- function2.hpp	2022-06-16 19:56:34.645027778 +0000
+++ function2.hpp-fixed	2022-06-16 15:54:34.989443571 +0000
@@ -573,6 +573,7 @@
         auto obj = retrieve<T>(std::integral_constant<bool, IsInplace>{},      \
                                data, capacity);                                \
         auto box = static_cast<T CONST VOLATILE*>(obj);                        \
+       if(box == nullptr) throw_or_abort##NOEXCEPT(std::integral_constant<bool, false>{});      \
         return invocation::invoke(                                             \
             static_cast<std::decay_t<decltype(box->value_)> CONST VOLATILE     \
                             REF>(box->value_),                                 \

Your Environment

  • OS: Linux, Ubuntu 20.04 and 22.04
  • Compiler and version: GCC 11.1.0, 11.2.0, 12.0.1 (packaged in Ubuntu)
  • Standard library (if non default): default

std::is_nothrow_move_constructible_v<fu2::unique_function<void()>> possible?

@Naios

Would it be possible to support

static_assert(std::is_nothrow_move_constructible_v<fu2::unique_function<void()>>);

?
I tried it with gcc (GCC) 8.2.1 20181127 and clang version 7.0.1 (tags/RELEASE_701/final) on Arch Linux. My use case is to store fu2::unique_functions in a std::vector, but upon resizing the vector, the assertion

assert(std::is_copy_constructible<T>::value && "The box is required to be copyable here!");

triggers, since the vector copies the elements to the new storage instead of moving.
I don't understand the internals enough to reason about the feasability of this feature. As a workaround, preallocating enough storage in the vector works for me, as well as wrapping fu2::unique_function into a std::unique_ptr, so this feature is more a Quality Of Life improvement.

Incomprehensible error message on clang

@Naios

When trying to initialize fu2::function_view<float(float)> with an object of type fu2::function<float(float) const>, clang 14 spews out an incomprehensible error message without a proper "instantiation stack". It is possible to infer what the problem is from const T not being castable to void* inside address_taker, but I think a proper concept or static assert based error message would be much preferred.


Commit Hash

2d3a878

Expected Behavior

Pretty error message, "cannot initialize a non-const callable function view with a const-only callable function".

Actual Behavior

Incomprehensible error message

Steps to Reproduce

Try to initialize a fu2::function_view<float(float)> with an object of type fu2::function<float(float) const>

Your Environment

  • OS: Windows
  • Compiler and version: Clang-cl 14
  • Standard library (if non default): MSVC

Use strongly typed configuration options instead of multiple bools

@Naios Here are some suggestions about fu2::function_base.

  1. There are too many boolean template parameters. It's hard to imagine what specific combination of policies are given if we just write
template<typename Arg>
using my_consumer = fu2::function_base<true, false, fu2::capacity_fixed<100U>,
                                       true, false, void(Arg)&&>;

In my opinion, better alternatives might be:

  • Use separate enum types for each policy parameter, or
  • Change policy parameters from non-type parameters to type parameters, and define new empty type for each policy.

The second approach might require more template metaprogramming, but it's open-ended (users can add more options at their will) while the enum approach is closed-ended. This might be either pros or cons, though.

I recommend the enum approach, and I think there is virtually no downside of it compared to the boolean approach, except that the implementation might be a bit more verbose.

  1. This one is about README. I'm not sure what HasStrongExceptGuarantee is meant to mean. I mean, I know what strong exception guarantee means in general, but I think it might be better to explicitly say (1) where are the places fu2::function_base is guarding against exceptions when HasStrongExceptGuarantee is set to be true, and (2) exactly what invariants are preserved. I assumed these are about copy assignment, is that correct?

Thanks!

Reference parameters

The following code does not compile on MSVC version 19.12.25830.2 (Visual Studio 2017 15.5.1):

int foo(int& i) { return i; }
// ...
fu2::function<int(int&)> f = foo;

With the errors:

function2.hpp(355): error C2672: 'fu2::v5::detail::invocation::invoke': no matching overloaded function found
...
function2.hpp(355): error C2893: Failed to specialize function template 'unknown-type fu2::v5::detail::invocation::invoke(Callable &&,Args &&...) noexcept(<expr>)'
function2.hpp(355): note: With the following template arguments:
function2.hpp(355): note: 'Callable=int (__cdecl *&)(int &)'
function2.hpp(355): note: 'Args={int}'

However, I can get around this using std::reference_wrapper:

fu2::function<int(std::reference_wrapper<int>)> f = foo;

Is this an issue on other compilers? I thought I'd share my workaround in case others run up against this issue and maybe see if it can be fixed, but I don't have enough template metaprogramming experience to understand what's going wrong here.

New release possible?

Hi!

I'd like to use the library. However, it looks like there have been additional fixes since the last release (2.2.0).
Is it possible to get a new release including them?

Thanks!

Wording

@Naios

fu2::function<void(int, float) const>
// Return type ~^   ^     ^     ^
// Arguments ~~~~~~~|~~~~~|     ^
// Qualifier ~~~~~~~~~~~~~~~~~~~|

"Arguments" seems the wrong term, and it should be "parameters". They are indeed parts of an argument (void(int, float) const) in the sense of type arguments of the template function, but not the function arguments in the function call syntax used in client code. It seems incorrect to put it next to "return type".

Calling rvalue functions twice

@Naios


Commit Hash

Git Tag 3.1.0

Expected Behavior

As Rvalue functions are meant to be single shot functions, the second invocation should result in raising a bad_function_call

Actual Behavior

Output:

10
10

Steps to Reproduce

#include <function2.hpp>
#include <iostream>

int main() {
    fu2::function<void(int)&&> fun = [](int x) {std::cout << x << std::endl;};
    std::move(fun)(10);
    std::move(fun)(10);
    return 0;
}

Your Environment

  • OS: Ubuntu 18.04.1 LTS
  • Compiler and version: gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)

Additional Questions

As I wish to use your library in a large GPL3 project, I cannot use the new Version 4.0, due to its cmake version higher than 3.5.
Why did you increase the Cmake version? It seems to work fine for me. Has anyone suggestions how to use the newer versions with old cmake?

function_view cannot bind to const lambda

@Naios


Expected Behavior

The const-ness of the callable should be propagated to the erased function pointer

Actual Behavior

In file included from main.cpp:1:0:
function2.hpp: In instantiation of ‘static void* fu2::abi_400::detail::type_erasure::address_taker<T, <template-parameter-1-2> >::take(O&&) [with O = const main()::<lambda()>&; T = main()::<lambda()>; <template-parameter-1-2> = void]’:
function2.hpp:1184:51:   required from ‘constexpr fu2::abi_400::detail::type_erasure::erasure<false, Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::erasure(T&&) [with T = const main()::<lambda()>&; Config = fu2::abi_400::detail::config<false, true, fu2::capacity_default>; bool IsThrowing = true; bool HasStrongExceptGuarantee = false; Args = {int()}]’
function2.hpp:1376:72:   required from ‘constexpr fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::function(T&&) [with T = const main()::<lambda()>&; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::enable_if_not_convertible_to_this<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::enable_if_can_accept_all_t<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::assert_wrong_copy_assign_t<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::assert_no_strong_except_guarantee_t<T>* <anonymous> = 0; Config = fu2::abi_400::detail::config<false, true, fu2::capacity_default>; bool IsThrowing = true; bool HasStrongExceptGuarantee = false; Args = {int()}]’
main.cpp:9:42:   required from here
function2.hpp:249:26: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
     return std::addressof(obj);

Steps to Reproduce

#include "function2.hpp"
int main()
{
  const auto callable = []{ 
      return 5;
  };  

  fu2::function_view<int()> view(callable);
}
g++ -std=c++14 main.cpp

Your Environment

>$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Undefined std::free, std::abort and std::malloc

If I do not include cstdlib before including the header file, I receive the following error message for std::free, std::abort and std::malloc:

error : no member named 'abort' in namespace 'std'

Should the header include cstdlib itself?

Test size_match_layout in regressions.cpp fails on i586/i686

@Naios


Commit Hash

2d3a878

Expected Behavior

make -k test should be successful

Actual Behavior

The test size_match_layout fails on i586/i686:

[ RUN      ] regression_tests.size_match_layout
/tmp/function2/test/regressions.cpp:62: Failure
Expected equality of these values:
  sizeof(fn)
    Which is: 48
  fu2::detail::object_size::value
    Which is: 32
[  FAILED  ] regression_tests.size_match_layout (0 ms)

Steps to Reproduce

I cloned the repo (commit - 2d3a878) and was building on Slackware 15.0 (32bit)

$ mkdir build && (cd build && cmake .. && make && make -k test)
-- The CXX compiler identification is GNU 11.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/function2/build
[  5%] Building CXX object test/CMakeFiles/function2_playground.dir/playground.cpp.o
[ 11%] Linking CXX executable function2_playground
[ 11%] Built target function2_playground
[ 16%] Building CXX object test/CMakeFiles/gtest.dir/googletest/googletest/src/gtest-all.cc.o
In file included from /tmp/function2/test/googletest/googletest/src/gtest-all.cc:43:
/tmp/function2/test/googletest/googletest/src/gtest-death-test.cc: In function ‘bool testing::internal::StackGrowsDown()’:
/tmp/function2/test/googletest/googletest/src/gtest-death-test.cc:1012:24: warning: ‘dummy’ may be used uninitialized [-Wmaybe-uninitialized]
 1012 |   StackLowerThanAddress(&dummy, &result);
      |   ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
/tmp/function2/test/googletest/googletest/src/gtest-death-test.cc:1002:13: note: by argument 1 of type ‘const void*’ to ‘void testing::internal::StackLowerThanAddress(const void*, bool*)’ declared here
 1002 | static void StackLowerThanAddress(const void* ptr, bool* result) {
      |             ^~~~~~~~~~~~~~~~~~~~~
/tmp/function2/test/googletest/googletest/src/gtest-death-test.cc:1010:7: note: ‘dummy’ declared here
 1010 |   int dummy;
      |       ^~~~~
[ 22%] Building CXX object test/CMakeFiles/gtest.dir/googletest/googletest/src/gtest_main.cc.o
[ 27%] Linking CXX static library libgtest.a
[ 27%] Built target gtest
[ 33%] Building CXX object test/CMakeFiles/function2_tests.dir/assign-and-constructible-test.cpp.o
[ 38%] Building CXX object test/CMakeFiles/function2_tests.dir/build-test.cpp.o
[ 44%] Building CXX object test/CMakeFiles/function2_tests.dir/empty-function-call-test.cpp.o
[ 50%] Building CXX object test/CMakeFiles/function2_tests.dir/functionality-test.cpp.o
[ 55%] Building CXX object test/CMakeFiles/function2_tests.dir/noexcept-test.cpp.o
[ 61%] Building CXX object test/CMakeFiles/function2_tests.dir/self-containing-test.cpp.o
[ 66%] Building CXX object test/CMakeFiles/function2_tests.dir/standard-compliant-test.cpp.o
[ 72%] Building CXX object test/CMakeFiles/function2_tests.dir/type-test.cpp.o
[ 77%] Building CXX object test/CMakeFiles/function2_tests.dir/multi-signature-test.cpp.o
[ 83%] Building CXX object test/CMakeFiles/function2_tests.dir/regressions.cpp.o
/tmp/function2/test/regressions.cpp: In function ‘fu2::unique_function<void()> issue_14_create()’:
/tmp/function2/test/regressions.cpp:137:19: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
  137 |   return std::move(func);
      |          ~~~~~~~~~^~~~~~
/tmp/function2/test/regressions.cpp:137:19: note: remove ‘std::move’ call
[ 88%] Building CXX object test/CMakeFiles/function2_tests.dir/view-test.cpp.o
[ 94%] Building CXX object test/CMakeFiles/function2_tests.dir/overload-test.cpp.o
[100%] Linking CXX executable function2_tests
[100%] Built target function2_tests
Running tests...
Test project /tmp/function2/build
    Start 1: function2-unit-tests
1/1 Test #1: function2-unit-tests .............***Failed    0.01 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.01 sec

The following tests FAILED:
          1 - function2-unit-tests (Failed)
Errors while running CTest
Output from these tests are in: /tmp/function2/build/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
make: *** [Makefile:112: test] Error 8

Your Environment

  • OS: Slackware 15.0 (i586)
  • Compiler and version: GCC 11.2.0
  • Standard library (if non default): glibc-2.33

I also tried this in a debian docker container (docker run --rm -it --platform linux/386 debian:10 ...) and it failed the same test, so do not think this is Slackware related.

I also checked this on alpine 32bit, and the test does pass there - though this is with musl - docker run --rm -it --platform linux/386 alpine:3.16 ...

The test also passes on Slackwarearm-15.0, which is 32bit armv7.

Compilation error of fu2::unique_function having a capture [ std::vector< std::vector < std::unique_ptr<int> > > ]

@Naios

The code attached does not compile. This is probably because of the two dimensional vector of uncopyable objects (unique_ptrs)

By uncommenting the dummy variable at the line 31 in the capture the code compiles and runs as expected


Commit Hash

Latest commit e30dbbe on 13 Apr

Expected Behavior

To be compilable, and functioning

Actual Behavior

It doesn't compile, error message:

D:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev0\mingw64\lib\gcc\x86_64-w64-mingw32\7.2.0\include\c++\bits\stl_construct.h|75|error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete]'|

Steps to Reproduce

Please use the example code given in the attachment

main.zip

Your Environment

  • OS: { Windows } same behavior on Linux
  • Compiler and version: { MinGW w64, GCC version 7.2, but the same behavior on Linux
  • Standard library - default

Support and propagate noexcept-qualified function types

@Naios

Basically, I want this to work

// This works today
using yesexcept_func = fu2::function<void()>;
static_assert(!noexcept(std::declval<yesexcept_func>()()));

// This fails to compile
using noexcept_func = fu2::function<void() noexcept>;
static_assert(noexcept(std::declval<noexcept_func>()()));

https://godbolt.org/g/zxVvKT
Propagation may require c++17.

(Removed most of the issue template boilerplate since it doesn't seem to apply to feature requests)

Problems compiling a test program under MSVS 2017

@Naios

Hello Naios,

I have tried to use your header only library in my test project on MSVS 2017 version 15.3.5 and I get compiler errors. Let me explain the case:
I have 3 header files (A.h, B.h, C.h) which look as follows:
A.h

#pragma once

#include "function2\function2.hpp"

struct A {

   fu2::unique_function<bool(int, int)> eq_int_fn;

   A() {
      eq_int_fn = [](int a, int b) -> bool {return a == b; };
   }
};

B.h

#pragma once

#include "function2\function2.hpp"
#include <string>

struct B {

   fu2::function<bool(std::string, std::string)> eq_str_fn;

   B() {
      eq_str_fn = [](std::string a, std::string b) -> bool {return a == b; };
   }
};

C.h

#pragma once

#include "A.h"
#include "B.h"
#include "function2\function2.hpp"

struct C: public A, public B {

   fu2::function<bool(long, long)> eq_long_fn = [](long a, long b) -> bool {return a == b; };

};

and func2test.cpp.h

#include <iostream>
#include "C.h"
using namespace std;
int main(int argc, char* arc[])
{
   C c;
   cout << "Equal: " << c.eq_long_fn(10, 10) << endl;
   cout << "Equal: " << c.eq_int_fn(10, 11) << endl;
   cout << "Equal: " << c.eq_str_fn("A", "B") << endl;
   return 0;
}

Now if I set Project->Properties->C/C++->Language->C++ Language Standard setting to "ISO C++17 Standard (/std:c++17)" or "ISO C++ Latest Draft Standard (/std:c++latest)" the I get compilation errors (see below compiler log). In case if I set it to "ISO C++14 Standard (/std:c++14)" then everything works fine.
Is this a bug or is this designed to work in such a way?

Compiler log:

1>------ Build started: Project: func2-test, Configuration: Debug x64 ------
1>func2test.cpp
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...)>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...)>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) const &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(522): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<Ret(Args...) volatile const &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...),Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...),Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...)>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...)>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) &,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) &,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const &,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const &,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile &,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile &,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const &,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const &,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const &>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const &>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) &&,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) &&,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const &&,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) const &&,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) const &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile &&,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile &&,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const &&,Next,Signatures...>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,Function,Ret(Args...) volatile const &&,Next,Signatures...>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): error C2953: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const &&>': class template has already been defined
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(706): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index,fu2::abi_400::detail::function<Config,Property>,Ret(Args...) volatile const &&>'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1301): error C2504: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>,bool (int,int)>': base class undefined
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\a.h(7): note: see reference to class template instantiation 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>' being compiled
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2794: 'pointer_type': is not a member of any direct or indirect base class of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(739): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::invocation_table::invoke_table<bool (int,int)>' being compiled
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1014): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::tables::vtable<Property>' being compiled
1>        with
1>        [
1>            Property=fu2::abi_400::detail::property<true,false,bool (int,int)>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1343): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::erasure<true,Config,fu2::abi_400::detail::property<true,false,bool (int,int)>>' being compiled
1>        with
1>        [
1>            Config=fu2::abi_400::detail::config<true,false,fu2::capacity_default>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2938: 'function_pointer_of<bool(int,int)>' : Failed to specialize alias template
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1472): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>,bool (int,int)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1297): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>,bool (int,int)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1472): error C2873: '()': symbol cannot be used in a using-declaration
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1242): error C2903: 'callable': symbol is neither a class template nor a function template
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\a.h(10): note: see reference to class template instantiation 'fu2::abi_400::detail::accepts_one<A::{ctor}::<lambda_480bcf0fb16eb88925f8ee9c4addaec8>,bool (int,int),fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>>' being compiled
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1242): error C2062: type 'unknown-type' unexpected
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1243): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1245): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1245): error C2065: 'value': undeclared identifier
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1246): error C2903: 'callable': symbol is neither a class template nor a function template
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1246): error C2062: type 'unknown-type' unexpected
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1247): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (int,int)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1247): error C2975: 'RequiresNoexcept': invalid template argument for 'fu2::abi_400::detail::invocation::is_noexcept_correct', expected compile-time constant expression
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(204): note: see declaration of 'RequiresNoexcept'
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\a.h(10): error C2679: binary '=': no operator found which takes a right-hand operand of type 'A::{ctor}::<lambda_480bcf0fb16eb88925f8ee9c4addaec8>' (or there is no acceptable conversion)
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1427): note: could be 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>::operator =(std::nullptr_t)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1394): note: or       'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>::operator =(fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>> &&) noexcept(<expr>)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1393): note: or       'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>::operator =(const fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>> &)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\a.h(10): note: while trying to match the argument list '(fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,false,Capacity>,fu2::abi_400::detail::property<true,false,bool (int,int)>>, A::{ctor}::<lambda_480bcf0fb16eb88925f8ee9c4addaec8>)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1301): error C2504: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>,bool (std::string,std::string)>': base class undefined
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\b.h(8): note: see reference to class template instantiation 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>' being compiled
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2794: 'pointer_type': is not a member of any direct or indirect base class of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(739): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::invocation_table::invoke_table<bool (std::string,std::string)>' being compiled
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1014): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::tables::vtable<Property>' being compiled
1>        with
1>        [
1>            Property=fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1343): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::erasure<true,Config,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>' being compiled
1>        with
1>        [
1>            Config=fu2::abi_400::detail::config<true,true,fu2::capacity_default>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2938: 'function_pointer_of<bool(std::string,std::string)>' : Failed to specialize alias template
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1472): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>,bool (std::string,std::string)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1297): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>,bool (std::string,std::string)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1243): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1245): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1247): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (std::string,std::string)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\b.h(11): error C2679: binary '=': no operator found which takes a right-hand operand of type 'B::{ctor}::<lambda_f3910cc3aea2b6888fed6879cd649046>' (or there is no acceptable conversion)
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1427): note: could be 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>::operator =(std::nullptr_t)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1394): note: or       'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>::operator =(fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>> &&) noexcept(<expr>)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1393): note: or       'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>> &fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>::operator =(const fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>> &)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\b.h(11): note: while trying to match the argument list '(fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (std::string,std::string)>>, B::{ctor}::<lambda_f3910cc3aea2b6888fed6879cd649046>)'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1301): error C2504: 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (long,long)>>,bool (long,long)>': base class undefined
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\c.h(9): note: see reference to class template instantiation 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (long,long)>>' being compiled
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2794: 'pointer_type': is not a member of any direct or indirect base class of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(739): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::invocation_table::invoke_table<bool (long,long)>' being compiled
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1014): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::tables::vtable<Property>' being compiled
1>        with
1>        [
1>            Property=fu2::abi_400::detail::property<true,false,bool (long,long)>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1343): note: see reference to class template instantiation 'fu2::abi_400::detail::type_erasure::erasure<true,Config,fu2::abi_400::detail::property<true,false,bool (long,long)>>' being compiled
1>        with
1>        [
1>            Config=fu2::abi_400::detail::config<true,true,fu2::capacity_default>
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(535): error C2938: 'function_pointer_of<bool(long,long)>' : Failed to specialize alias template
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1472): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (long,long)>>,bool (long,long)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1297): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<0,fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (long,long)>>,bool (long,long)>'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1243): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1245): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(1247): error C2027: use of undefined type 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\lib\function2\include\function2\function2.hpp(471): note: see declaration of 'fu2::abi_400::detail::type_erasure::invocation_table::function_trait<First>'
1>        with
1>        [
1>            First=bool (long,long)
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\c.h(9): error C2664: 'fu2::abi_400::detail::function<fu2::abi_400::detail::config<true,true,Capacity>,fu2::abi_400::detail::property<true,false,bool (long,long)>>::function(std::nullptr_t)': cannot convert argument 1 from 'C::<lambda_f6cd4ad39bd83322785042c7b76f3bda>' to 'std::nullptr_t'
1>        with
1>        [
1>            Capacity=fu2::capacity_default
1>        ]
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\c.h(9): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\func2test.cpp(9): error C2064: term does not evaluate to a function taking 2 arguments
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\func2test.cpp(10): error C2064: term does not evaluate to a function taking 2 arguments
1>d:\programming\cpp\3rdparty\tmp_project\func2-test\src\func2test.cpp(11): error C2064: term does not evaluate to a function taking 2 arguments
1>Done building project "func2-test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


Commit Hash

On the latest commit (I think the commit hash is fd56e02). I downloaded zip on 28.01.2019.
Sorry for my bad knowledge about this stuff. I am very new to this stuff.

Expected Behavior

I think the compiling should go through also with the settings for C++17 on MSVS 2017.

Actual Behavior

Compiler error if Language Standard is set to c++17 or latest.

Steps to Reproduce

Written above in the description of my problem.

Your Environment

  • OS: Windows 10
  • Compiler and version: MSVC Version 19.11.25508.2 for x64
  • Standard library (if non default):
  • Additional info regarding MSVS installation:
Microsoft Visual Studio Professional 2017 
Version 15.3.5
VisualStudio.15.Release/15.3.5+26730.16
Microsoft .NET Framework
Version 4.7.03056

Installed Version: Professional

Visual Basic 2017   00370-20004-20195-AA847
Microsoft Visual Basic 2017

Visual C# 2017   00370-20004-20195-AA847
Microsoft Visual C# 2017

Visual C++ 2017   00370-20004-20195-AA847
Microsoft Visual C++ 2017

JavaScript Language Service   2.0
JavaScript Language Service

MenuCommands Extension   1.0
MenuCommands Visual Studio Extension Detailed Info

Microsoft JVM Debugger   1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft MI-Based Debugger   1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards   1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio VC Package   1.0
Microsoft Visual Studio VC Package

Visual C++ for Linux Development   1.0.7
Visual C++ for Linux Development

Visual Studio Code Debug Adapter Host Package   1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Missing explicit bool operator()

std::function have an explicit bool operator to allow it's user to evaluate if it contains something or not.
Your function implementations does not, but it's necessary for code that stores optional callbacks and want to check if there is something to call before calling.

Looking at the code, it seems to me that in storage_t, impl_t could be set to nullptr when there is nothing assigned. I'm trying this solution at the moment but I don't know if it's the best one yet.

function2 seems to fail when modeling functions returning references

@Naios

Perhaps I'm misunderstanding something, but I have a use-case where fu2::function & fu2::unique_function usage fails to compile while the same code compiles and runs fine using std::function.


Commit Hash

noticed using function2.hpp sources from commit 7cd9537

Expected Behavior

fu2::function is a drop in replacement for std::function :-)

Actual Behavior

fu2::function and fu2::unique_function usage fails to compile when modeling functions returning references

Steps to Reproduce

run the following code - it should fail to compile, and then try commenting out the bottom part related to fu2::function & fu2::unique_function objects modeling a reference returning function, which should make the program work as expected:

#include <function2.hpp>

#include <iostream>
#include <functional>

class Blinky
{
public:
	Blinky(const char* data) : data_(data) {}
	Blinky(Blinky&&) = default;
	Blinky& operator=(Blinky&&) = default;
	
	const char* data() const { return data_; }

private:
	Blinky(const Blinky&) = delete;
	void operator=(const Blinky&) = delete;

private:
    const char* data_;
};
Blinky blinky("42");

typedef Blinky& AAAR;
AAAR xxxgr() { return blinky; }
const char* get_data(AAAR aaa) { return aaa.data(); }

typedef Blinky* AAAP;
AAAP xxxgp() { return &blinky; }
const char* get_data(AAAP aaa) { return aaa->data(); }

int main()
{
    // std::function works with all return types
    {
    	std::function<AAAR ()> xxx((xxxgr));
    	std::cout << "std::function with reference type: " << get_data(xxx()) << '\n';
    }
    {
    	std::function<AAAP ()> xxx((xxxgp));
    	std::cout << "std::function with pointer type: " << get_data(xxx()) << '\n';
    }
	
    // function2 variants work with pointer return types
    {
    	fu2::function<AAAP ()> xxx((xxxgp));
    	std::cout << "fu2::function with pointer type: " << get_data(xxx()) << '\n';
    }
    {
    	fu2::unique_function<AAAP ()> xxx((xxxgp));
    	std::cout << "fu2::unique_function with pointer type: " << get_data(xxx()) << '\n';
    }

    // function2 variants fail with reference return types
    {
    	fu2::function<AAAR ()> xxx((xxxgr));
    	std::cout << "fu2::function with reference type: " << get_data(xxx()) << '\n';
    }
    {
    	fu2::unique_function<AAAR ()> xxx((xxxgr));
    	std::cout << "fu2::unique_function with reference type: " << get_data(xxx()) << '\n';
    }
}

on a successful run I get the following output:

std::function with reference type: 42
std::function with pointer type: 42
fu2::function with pointer type: 42
fu2::unique_function with pointer type: 42

when testing a failed compile on https://www.onlinegdb.com/online_c++_compiler, I get the following output:

main.cpp: In instantiation of ‘constexpr auto fu2::abi_400::detail::type_erasure::tables::vtable<fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, FormalArgs ...> >::invoke(Args&& ...) const [with long unsigned int Index = 0ul; Args = {fu2::abi_400::detail::type_erasure::data_accessor*, const long unsigned int&}; bool IsThrowing = true; bool HasStrongExceptGuarantee = false; FormalArgs = {Blinky&()}]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',1215)">main.cpp:1215:36</span>:   required from ‘static constexpr auto fu2::abi_400::detail::type_erasure::erasure<IsOwning, Config, Property>::invoke(Erasure&&, Args&& ...) [with long unsigned int Index = 0ul; Erasure = fu2::abi_400::detail::type_erasure::erasure<true, fu2::abi_400::detail::config<true, true, fu2::capacity_default>, fu2::abi_400::detail::property<true, false, Blinky&()> >&; Args = {}; bool IsOwning = true; Config = fu2::abi_400::detail::config<true, true, fu2::capacity_default>; Property = fu2::abi_400::detail::property<true, false, Blinky&()>]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',775)">main.cpp:775:1</span>:   required from ‘Ret fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index, fu2::abi_400::detail::function<Config, Property>, Ret(Args ...)>::operator()(Args ...) [with long unsigned int Index = 0ul; Config = fu2::abi_400::detail::config<true, true, fu2::capacity_default>; Property = fu2::abi_400::detail::property<true, false, Blinky&()>; Ret = Blinky&; Args = {}]’
<span class="error_line" onclick="ide.gotoLine('main.cpp',1825)">main.cpp:1825:73</span>:   required from here
main.cpp:995:45: error: ‘Blinky::Blinky(const Blinky&)’ is private within this context
     return thunk(std::forward<Args>(args)...);
                                             ^
main.cpp:1784:2: note: declared private here
  Blinky(const Blinky&) = delete;
  ^~~~~~
main.cpp:995:45: error: use of deleted function ‘Blinky::Blinky(const Blinky&)’
     return thunk(std::forward<Args>(args)...);
                                             ^
main.cpp:1784:2: note: declared here
  Blinky(const Blinky&) = delete;
  ^~~~~~
main.cpp: In instantiation of ‘Ret fu2::abi_400::detail::type_erasure::invocation_table::operator_impl<Index, fu2::abi_400::detail::function<Config, Property>, Ret(Args ...)>::operator()(Args ...) [with long unsigned int Index = 0ul; Config = fu2::abi_400::detail::config<true, true, fu2::capacity_default>; Property = fu2::abi_400::detail::property<true, false, Blinky&()>; Ret = Blinky&; Args = {}]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',1825)">main.cpp:1825:73</span>:   required from here
main.cpp:771:38: error: invalid initialization of non-const reference of type ‘Blinky&’ from an rvalue of type ‘Blinky’
           std::forward<Args>(args)...);                                        \
                                      ^
main.cpp:495:3: note: in expansion of macro ‘FU2_DEFINE_FUNCTION_TRAIT’
   F(, , , , &)                                                                 \
   ^
main.cpp:775:1: note: in expansion of macro ‘FU2_DETAIL_EXPAND_QUALIFIERS’
 FU2_DETAIL_EXPAND_QUALIFIERS(FU2_DEFINE_FUNCTION_TRAIT)
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Your Environment

tested on https://www.onlinegdb.com/online_c++_compiler

  • OS: don't really know but I expect some kind of Linux :-)
  • Compiler and version: g++ 5.4.1 c++14
  • Standard library (if non default): default

And quite likely similar errors occur using Visual Studio 2017 Update 3 compiler as I got to this example by attempting to trim down some code giving a warning on that compiler about a reference to a local variable or a temporary being returned. (The warning output there is completely useless as it just points to some FU2_DETAIL_EXPAND_QUALIFIERS() macro call and shows no additional code or information :-()

can not store a call to access data member

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

   const Foo foo1(1);
//   fu2::function<int(const Foo&)> fn3 = &Foo::num_; // report fail here
    std::function<int(const Foo&)> stdfn3 = &Foo::num_;

    std::cout << stdfn3(2) << std::endl;
    std::cout << stdfn3(foo1) << std::endl;

error: conversion from 'int Foo::*' to non-scalar type....
gcc version 6.3.0 (GCC)

but it worked with std::bind

fu2::function<int(const Foo&)> fn5 = std::bind(&Foo::num_, _1); // this is ok
    cout << fn5(foo1) << endl;

Benchmark

[size]
stdex::function<int(int)>: 24
std::function<int(int)>: 64
multifunction<int(int)>: 32
boost::function<int(int)>: 40
func::function<int(int)>: 32
generic::delegate<int(int)>: 56
ssvu::FastFunc<int(int)>: 48
fu2::function<int(int)>: 48

[function_pointer]
Perf< no_abstraction >: 1.8453771774 [s] {checksum: 0}
Perf< stdex::function<int(int)> >: 2.4105954477 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.4198029305 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 2.3328036636 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 2.3304626042 [s] {checksum: 0}
Perf< func::function<int(int)> >: 2.3457726414 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.4707737688 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 2.4537932347 [s] {checksum: 0}

[compile_time_function_pointer]
Perf< no_abstraction >: 0.4627506562 [s] {checksum: 0}
Perf< stdex::function<int(int)> >: 1.8527154205 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.1748118553 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 1.8284414304 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.8696178882 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.8735874566 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.0570920540 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 1.8556191180 [s] {checksum: 0}

[compile_time_delegate]
Perf< no_abstraction >: 0.7039404257 [s] {checksum: 0}
Perf< stdex::function<int(int)> >: 1.7530071899 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.4055553430 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 1.9321503317 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.8345237684 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.8667835486 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.0517126248 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 2.4226851675 [s] {checksum: 0}

[lambda]
Perf< stdex::function<int(int)> >: 1.8489533035 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.0438002358 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 1.7777772594 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.7765925782 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.8882079590 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.0324261767 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 1.9082934215 [s] {checksum: 0}

[lambda_capture]
Perf< stdex::function<int(int)> >: 1.8784627199 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.2231564274 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 1.7945276375 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.8343915843 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.8153822564 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.2836924233 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 2.1069581436 [s] {checksum: 0}

[heavy_functor]
Perf< stdex::function<int(int)> >: 1.7700371764 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.0328532093 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 1.7518178434 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.8180318492 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.7967380679 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.0138015825 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 2.4916856157 [s] {checksum: 0}

[non_assignable]
Perf< stdex::function<int(int)> >: 1.8585035321 [s] {checksum: 0}
Perf< std::function<int(int)> >: 2.5214077707 [s] {checksum: 0}
Perf< multifunction<int(int)> >: 2.0703316205 [s] {checksum: 0}
Perf< boost::function<int(int)> >: 1.8532929876 [s] {checksum: 0}
Perf< func::function<int(int)> >: 1.8794004499 [s] {checksum: 0}
Perf< generic::delegate<int(int)> >: 2.4986664950 [s] {checksum: 0}
Perf< fu2::function<int(int)> >: 2.4160246404 [s] {checksum: 0}

C++17 noexcept support

With C++17 the noexcept-specification became part of the function type. Do you have any support for it? The documentation doesn't mention it, but I found the specifier in your source.

It would be great if function2 would support noexcept for function types. Besides move-only callables this is the second big leak of std::function. (https://wg21.link/p0045 tries to fix this.)

If your current implementation already supports noexcept, it would be nice if you could add in the documentation in which way. Otherwise it would be nice if you would add this to the todos for the next version.

Thanks for the great library by the way! 😊

Possible typo in property template

While looking for a unique_function implementation I cam across this lib. I was wondering about the following line:

static constexpr auto const is_strong_exception_guaranteed = Throws;

That looks suspiciously like a typo. Shouldn't it be instead:

  static constexpr auto const is_strong_exception_guaranteed = HasStrongExceptGuarantee;

IsThrowing affects movability of fu2::function

@Naios


Commit Hash

d2acdb6 (release 4.0.0)

Expected Behavior

When using fu2::function_base to create a custom unique_function with IsThrowing set to false, storing the custom unique_function in a std::vector should not invoke abort() on vector resize (due to the vector trying to call the copy constructor):

Actual Behavior

abort() is called when the vector tries to copy it's contents internally.

Steps to Reproduce

The following code calls abort() on functions.reserve(...):

#include <vector>
#include "function2.hpp"

template<typename Signature>
using UniqueFunction = fu2::function_base<true, false, fu2::capacity_default,
	false, false, Signature>;

int main(int argc, char* argv[])
{
	std::vector<UniqueFunction<void()>> functions;
	int x = 0;

	functions.emplace_back([&]()
	{
		++x;
	});

	functions.reserve(functions.size() + 1); //abort() called here

	return 0;
}

I have read that std::vector will only internally move the object on memory reallocation if the type's move constructor and assignment operator are marked as noexcept, therefore I tried changing the vector to std::vector<UniqueFunction<void() noexcept>> and adding noexcept to the lambda with no effect.

Changing IsThrowing to true corrects everything. Please let me know if I'm misunderstanding anything!

Your Environment

  • OS: Windows/iOS
  • Compiler and version: MSVC v141/Clang 10.0.0
  • Standard library (if non default): std

conan.io package?

Would you mind adding this library to conan.io so that other folks(already on conan) can consume it without having to manually copy-paste header each time?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.