Using `std::function` to call non-void function

后端 未结 3 763
一个人的身影
一个人的身影 2020-11-28 15:53

A while ago I used std::function pretty much like this:

std::function func = [](int i) -> int { return i; };
相关标签:
3条回答
  • 2020-11-28 16:11

    This looks like it may be ok for anonymous functions.

    Quote from http://www.alorelang.org/release/0.5/doc/std_function.html (this is not from the C++ standard library, however it looks like they are using something similar in there bindings down to C++)

    Function objects can only be created with a function definition, an anonymous function expression or by accessing a bound method using the dot (.) operator.

    Another way this could possibly be done is by storing the function pointer in auto as seen here: http://en.wikipedia.org/wiki/Anonymous_function (C++ section)

    0 讨论(0)
  • 2020-11-28 16:14

    Your use case is well-defined according to the standard.

    You are constructing a std::function from a callable object[1]

    §20.8.11.2.1/7:

    template<class F> function(F f);
    

    Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R.

    So is your f callable?

    §20.8.11.2/2 says:

    A callable object f of type F is Callable for argument types ArgTypes and return type R if the expres- sion INVOKE (f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.8.2).

    And the definition of INVOKE says:

    §20.8.2

    1. Define INVOKE (f, t1, t2, ..., tN) as follows: ... stuff dealing with member function/var pointers ... — f(t1, t2, ..., tN) in all other cases.

    2. Define INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) implicitly converted to R.

    And since any type can be implicitly converted to void, your code should be fine with a standards-conforming compiler. As pointed out by litb below, there isn't an implicit conversion to void so this isn't well defined.

    [1]: I think the lambda counts as a callable object here, although I don't have a reference for that. Your lambda could also be used as a function pointer as it captures no context

    0 讨论(0)
  • 2020-11-28 16:21

    Your code has undefined behavior. It may or may not work as you expect. The reason it has undefined behavior is because of 20.8.11.2.1 [func.wrap.func.con]/p7:

    Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R.

    For f to be Callable for return type R, f must return something implicitly convertible to the return type of the std::function (void in your case). And int is not implicitly convertible to void.

    I would expect your code to work on most implementations. However on at least one implementation (libc++), it fails to compile:

    test.cpp:7:30: error: no viable conversion from 'int (int)' to 'std::function<void (int)>'
        std::function<void(int)> ff = f;
                                 ^    ~
    

    Ironically the rationale for this behavior stems from another SO question.

    The other question presented a problem with std::function usage. The solution to that problem involved having the implementation enforce the Requires: clause at compile time. In contrast, the solution to this question's problem is forbidding the implementation from enforcing the Requires: clause.

    0 讨论(0)
提交回复
热议问题