Why is the converting constructor of std::packaged_task explicit, while the same constructor of std::function is not? I cannot find any reasoning for it.
This, for example, forces casting when passing a lambda as an argument for a function that has a packaged_task (or a reference to it) as a parameter:
void f1(std::function<void()>);
std::future<void> f2(std::packaged_task<void()>);
int main()
{
f1( []{ } ); // ok
auto fut = f2( []{ } ); // error
auto fut = f2( (std::packaged_task<void()>) []{ } ); // ok
fut.wait();
}
Consider following example. Lets create a template class that emulates class with non-explicit templated converting constructor.
The output will be
The template hijacks control in both cases! You actually cannot use copy\move constructors in such situation. A simplest way to avoid it is to make conversion explicit.
Output:
std::functionis copyable whilestd::packaged_taskhave to define custom move constructor and delete copying constructor.On an attempt to pass
std::function, in both cases nothing BAD would happen, the copy and move constructors are likely operate upon function pointer or reference to callable object,std::functionis designed to act upon any compatible callable, that includes itself.if you attempt to do that to do that to
std::packaged_task, the converting constructor may do something wrong or likely wouldn't compile because it wouldn't be able to work with instance of own class. A statement that looks like copy (but actually is .. a move? assignment?) would be possible.