Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using `std::function<void(...)>` to call non-void function

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

std::function<void(int)> func = [](int i) -> int { return i; };

Basically, I did this because I wanted to store different function objects in a std::function, but I didn't want to restrict the return types of these functions. Since this seemed to work, I went with it. But I'm not convinced that it is safe to use, and I haven't been able to find any documentation on it. Does anyone know whether this usage is legitimate? Or more generally, what the rules are for the object which can safely be assigned to a std::function?

Edit

For clarification, the issue I'm concerned with is that the lambda function returns an int, while func is declared with return type void. I'm not sure if this is OK, especially once a call to func() is made.

like image 319
Ken Wayne VanderLinde Avatar asked Feb 18 '12 08:02

Ken Wayne VanderLinde


People also ask

Should void functions have a return statement?

A function that does not return a value is called a non-value returning function (or a void function). A void function will automatically return to the caller at the end of the function. No return statement is required.

What are non void functions?

Functions that return are great for when we need to go through a lot of steps to get a value that we want to use in our code somewhere. Calling a non-void function tells the computer to head over to the function definition, do everything, and come back with the result once it's done.


2 Answers

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.

like image 154
Howard Hinnant Avatar answered Oct 01 '22 13:10

Howard Hinnant


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

like image 32
je4d Avatar answered Oct 01 '22 15:10

je4d