WG21-SG14 / SG14

A library for Study Group 14 of Working Group 21 (C++)
504 stars 52 forks source link

[inplace_function] Should [](){return 42;} be convertible to inplace_function<void()>? #150

Open Quuxplusone opened 5 years ago

Quuxplusone commented 5 years ago

Related to #149.

static void test_void_returning_function()
{
    stdext::inplace_function<void()> f = []() { return 42; };
    f = []() { return 42; };
    f();
}

The above test case currently does not compile. Clang's error message is:

In file included from inplace_function_test.cpp:2:
../SG14/inplace_function.h:105:15: error: void block should not return a value
            { return (*static_cast<C*>(storage_ptr))(
              ^
../SG14/inplace_function.h:211:31: note: in instantiation of function template specialization 'stdext::inplace_function_detail::vtable<void>::vtable<(lambda
      at inplace_function_test.cpp:412:42)>' requested here
        static const vtable_t vt{inplace_function_detail::wrapper<C>{}};
                              ^
inplace_function_test.cpp:412:42: note: in instantiation of function template specialization 'stdext::inplace_function<void (), 32,
      16>::inplace_function<(lambda at inplace_function_test.cpp:412:42), (lambda at inplace_function_test.cpp:412:42), void>' requested here
    stdext::inplace_function<void()> f = []() { return 42; };
                                         ^

If we fix #149, then we must make a design decision here: should this code compile (as it does with std::function), or should it fail to compile (because returning 42 from a function with signature void(int) usually indicates a programming error)? https://quuxplusone.github.io/blog/2019/01/06/hyper-function/ is related.

Quuxplusone commented 5 years ago

Survey of existing practice (that is, of people who provide a single-header implementation, because I'm lazy): https://godbolt.org/z/PGx6JA

std::function happily permits converting int(*)() to function<void()>.

boost::function happily permits converting int(*)() to function<void()>.

https://github.com/TartanLlama/function_ref tl::function_ref consistently forbids converting int(*)() to function<void()>.

https://github.com/Naios/function2 fu2::function claims to permit converting int(*)() to function<void()>, but if you try it, you get a hard error from the guts of the vtable.

After #155, inplace_function claims to permit converting int(*)() to function<void()>, but if you try it, you get a hard error from the guts of the vtable.

I'd be interested to learn what happens with folly::function; with HPX unique_function; and/or with MongoDB unique_function. But they're not single-header Godbolt-friendly, so I didn't really try hard.