Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why std::function::argument_type has been deprecated?

Tags:

I've seen on cppreference that std::function::argument_type was deprecated in C++17. What is the reason behind it? And what ISO WG21 paper was proposing that?

like image 725
Vincent Avatar asked Mar 10 '16 04:03

Vincent


People also ask

Is std :: bind deprecated?

Yes: std::bind should be replaced by lambda For almost all cases, std::bind should be replaced by a lambda expression. It's idiomatic, and results in better code. There is almost no reason post C++11 to use std::bind .

Why do we need std :: function?

std::function can hold function objects (including lambdas), as well as function pointers with the correct signature. So it is more versatile.

Why is std :: function slow?

If it is small, like 3-5 CPU instructions then yes std::function will make it slower, because std::function is not inlined into outer calling code. You should use only lambda and pass lambda as template parameter to other functions, lambdas are inlined into calling code.


2 Answers

The relevant papers are P0005R4 (which is the paper that was voted into the draft standard) and P0090R0 (which is referenced by P0005R4).

Quotes from P0090R0:

Q2. What's wrong with result_type, etc.?

A2. These C++98/03/TR1-era typedefs predated decltype and perfect forwarding. Previously, generic code had to request information from function objects before adapting them. Now, manually communicating that information is unnecessary. decltype supersedes result_type, because the compiler can simply report what the result of calling a function object with specific arguments will be. And perfect forwarding supersedes the argument_type family, since adaptors can simply take/store/forward arbitrary arguments.

In fact, these typedefs are worse than useless. They're counterproductive, because many callable objects lack them. Function pointers and pointers to members have always lacked them. ptr_fun(), which wrapped function pointers with these typedefs, was recently removed (see [1] again). Most importantly, lambdas have always lacked these typedefs, and they are the most important function objects of all. Generic lambdas are even more incompatible.

What this means is that if a user attempts to write generic code by using the result_type family of typedefs, their code won't be generic - it'll fail to handle lambdas, generic lambdas, function pointers, etc.

These typedefs should be removed because they've become actively harmful to modern code.

like image 137
cpplearner Avatar answered Sep 20 '22 01:09

cpplearner


The reason those typedefs exist are so things like not1, bind1st and friends, could query the callables passed to them and retrieve the type of the result of invoking the callable, its argument types etc.

To make their use palatable, a lot of support machinery, like unary_function, ptr_fun, mem_fun etc. were also defined. Notice how all of these are limited to adapting callables taking one or two arguments only, so they're rather limited in that sense.

Now that we have decltype that can be used to deduce a callable's return type, variadic templates and perfect forwarding to forward arbitrary number of arguments to functions, etc. the pre-C++11 mechanisms are way too cumbersome to use.

Stephan T Lavavej first proposed getting rid of these in C++17 in p0090r0. Relevant excerpts from the paper:

Q1. What are you proposing?
* Removing every mention of result_type, argument_type, first_argument_type, and second_argument_type ...
* Removing the negators not1() and not2(), which were powered by these typedefs.

Q2. What's wrong with result_type, etc.?
A2. These C++98/03/TR1-era typedefs predated decltype and perfect forwarding. Previously, generic code had to request information from function objects before adapting them. Now, manually communicating that information is unnecessary. decltype supersedes result_type, because the compiler can simply report what the result of calling a function object with specific arguments will be. And perfect forwarding supersedes the argument_type family, since adaptors can simply take/store/forward arbitrary arguments.

If you search the paper for [func.wrap.func], it talks specifically about removing the std::function typedefs you're asking about.

like image 42
Praetorian Avatar answered Sep 23 '22 01:09

Praetorian