Naios / function2

Improved and configurable drop-in replacement to std::function that supports move only types, multiple overloads and more
http://naios.github.io/function2
Boost Software License 1.0
539 stars 47 forks source link

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

Closed Rajveer86 closed 4 years ago

Rajveer86 commented 4 years ago

@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

Naios commented 4 years ago

This library was not written to work with Objective-C++.

If you would come up with a solution by yourself I would be happy to accept a PR, but this will not be fixed by me. Also I don't have the OSX Xcode toolchain available for development.

Rajveer86 commented 4 years ago

That's fair enough. It looks like conversion to block pointer is by design for lambda-block interopability in Objective-C++ (http://clang.llvm.org/docs/LanguageExtensions.html#interoperability-with-c-11-lambdas) so I've decided to just disable the bool() operator optimisation if compiled as Objective-C++ by defining FU2_WITH_NO_EMPTY_PROPAGATION.

Naios commented 4 years ago

Could you point out which part of the empty bool propagation is causing troubles with Objective-C?

Rajveer86 commented 4 years ago

Sure, it's any time where bool(callable) is performed (e.g. line 1139), I created a minimal example here.

Naios commented 4 years ago

But why? The library doesn't call bool(callable) on every callable which is passed to it but only the ones where this check is possible (guarded through specialization): https://github.com/Naios/function2/blob/7cd95374b0f1c941892bfc40f0ebb6564d33fdb9/include/function2/function2.hpp#L1361-L1394

The code which is from your stackoverflow question:

auto myLambda = [&, myHeapInt = std::move(myHeapInt)]()
    {
        myStackInt = *myHeapInt;
    };

    if(bool(myLambda)) //Error ar this point
    {
        *myHeapInt = 5;
    }

is never done by function2 because the specialization is smart enough to detect that it would throw a build error and also would not work in c++.

Rajveer86 commented 4 years ago

I see, so it's not an issue of the callable being converted to a block pointer at the bool(callable) callsites, but it's an issue of the callable passing the specialization when it shouldn't.

Rajveer86 commented 4 years ago

From what I can tell my example compiles fine in Xcode with Clang when compiled just as regular C++ and I can hit the line *myHeapInt = 5;, so this may be a problem with the specialisation incorrectly passing in Clang even as C++ (could be a Clang bug?) and then just failing in Objective-C++ due to the block pointer conversion causing a copy.