Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I assign a callable to a std::function with a different return type?

I want to store a function inside a std::function. I don't care about the return value when calling this stored function, so the std::function just returns void.

Is there any undefined behavior when the stored function gets called?

Take the following example as a reference, where the function is a lambda returning an int (Link to run):

#include <iostream>
#include <functional>
std::function<void(void)> f;
int main()
{
    f = []() -> int { std::cout << "Returning int\n";  return 0; };
    f(); // Is this UB in any way?
    return 0;
}

The question applies not only to lambdas, but to any callable, such as member functions, free functions, etc.

like image 406
Hamza Hajeir Avatar asked Dec 07 '25 06:12

Hamza Hajeir


1 Answers

Ignoring the return result is explicitly allowed.

You are using the template< class F > function& operator=( F&& f ); overload of operator=, which has the requirement:

This operator does not participate in overload resolution unless f is Callable for argument types Args... and return type R.

Which is

INVOKE<R>(f, std::declval<ArgTypes>()...) is well-formed in unevaluated context.

And std::function<R(Args...>::operator()(Args... args) is similarly defined as doing INVOKE<R>(f, std::forward<Args>(args)...), returning nothing in the case R is void.

The exposition-only operation INVOKE<R>(f, arg_0, arg_1, arg_2, ..., arg_N) is defined as follows:

  • If R is (possibly cv-qualified) void

    • static_cast<void>(INVOKE(f, arg_0, arg_1, arg_2, ..., arg_N)).

I.e. it explicitly discards the result by casting to void

like image 139
Caleth Avatar answered Dec 09 '25 19:12

Caleth