Reputation: 769
please look at the following code
#include <iostream>
#include <functional>
#include <string>
int main()
{
std::function<void(std::string&)> theFunc;
std::string foo = "0";
theFunc = [](std::string a) { a = "1"; }; // this compiles but has a different function signature
theFunc(foo);
std::cout << "foo should be 1 but is " << foo << std::endl;
theFunc = [](auto a) { a = "2"; }; // this infers the wrong type for auto(by val not by ref), creates the wrong function signature and compiles
theFunc(foo);
std::cout << "foo should be 2 but is " << foo << std::endl;
theFunc = [](std::string& a) { a = "3"; }; // this compiles and correctly manipulates the string
theFunc(foo);
std::cout << "foo should be 3 and is " << foo << std::endl;
theFunc = [](auto& a) { a = "4"; }; // this compiles and correctly manipulates the string
theFunc(foo);
std::cout << "foo should be 4 and is " << foo << std::endl;
std::cin.get();
}
In the code example we have one std::function assigned different types of lambdas.
The lambda 3 i understand because the function signature matches.
But lambda 1 creates a different function signature but compiles correctly.
Lambda 2 infers the wrong auto type (by val and not by ref) and compiles correctly.
Is this a feature or a bug? What do i missunderstand regarding the function class / lambdas and the auto type inference?
UPDATE:
Thanks for the answer Handy999 but why is the following not compiling then?
std::function<void(std::string)> theFunc2;
theFunc2 = [](std::string& a) { a = "1"; }; // this doesn't compile and has a different function signature
theFunc2(foo);
Upvotes: 4
Views: 219
Reputation: 776
Unlike function pointers, std::function
takes everything which can be called as specified. If necessary, it creates a small wrapper function (in the background).
In all cases the code
void smallWrapper(std::string& s) {
([](std::string a) { a = "1"; })(s);
}
void smallWrapper2(std::string& s) {
([](auto a) { a = "2"; })(s);
}
void smallWrapper3(std::string& s) {
([](std::string& a) { a = "3"; })(s);
}
void smallWrapper4(std::string& s) {
([](auto& a) { a = "4"; })(s);
}
can be called. auto
always deduces the base type, so always to std::string
. Thus case 2=case 1 and case 4=case 3. This is what std::function
does and what it should do.
For the 5th case, it is really as Caleth pointed out. You cannot call
([](std::string& a) { a = "5"; })("string");
since you cannot bind a reference to a temporary. (Here, the wrapper function would work. So, its not a very good model.) For const references, it works as usual:
([](const std::string& a) { a = "6"; })("string");
Upvotes: 5