I have the following piece of code and there are a couple of things that bother me the most:
#include <iostream>
#include <functional>
class Samp {
char str[10] = "Default";
public:
Samp(char s[]) { strcpy(str, s); printf("Constructor\n"); }
Samp(const Samp& s) { printf("Copy Constructor\n"); }
~Samp() { printf("Destructor\n"); }
char* out() {
return str;
}
friend std::ostream& operator<<(std::ostream& stream, const Samp& s) {
stream << s.str;
return stream;
}
};
void output(Samp s) {
std::cout << s << std::endl;
}
int main(int argc, const char * argv[]) {
std::function<void(Samp s)> o;
o = output;
o((char*)"Hello");
return 0;
}
On execution, the program provides the following output
Constructor
Copy Constructor
Default
Destructor
Destructor
Program ended with exit code: 0

The arguments to a std::function invocation are passed by perfect forwarding through to the callable object stored inside the std::function object.
So the behaviour of o(args...) is not the same as output(args...). Instead it is the same as:
output( std::forward<Args...>(args...) );
or in this concrete example,
output( std::forward<Samp>( (char *)"Hello" ) );
In this example we see that "perfect" forwarding is not so perfect, as this code has slightly different behaviour to output( (char *)"Hello" ); .
The signature of the chosen overload for forward is Samp&& forward(Samp&& arg);. So there must be a temporary materialized for the arg to bind to for the function call tostd::forward; that is the "Constructor" that you see.
Then the "Copy constructor" is initialization of the output function's parameter from the return value of std::forward. That could be a move operation, if Samp had a move-constructor.
Constructor and Copy of you class called in one place basicly. When you use youre function its create Samp S by construct and then copy it to void fnc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With