I am trying to understand the concept of currying and calling a function which concats three strings but by passing only two strings and using the second argument twice.
Copying strings is expensive. Since std::bind
thinks that the values of the placeholders are only used once, it performs a std::move
on the strings. This is done for each Parameter and as a consequence, either b
or c
is a moved, that means empty string.
You can change that behavior by explicitly saying what you mean, by passing the arguments by const-reference:
string concatthreestrings(string const& a,string const& b,string const& c)
Now, it should work.
I did a few tests using this smaller example that exhibits the same behavior you have:
#include <functional>
#include <iostream>
#include <string>
using std::string;
void print(string s1, string s2)
{
std::cout << s1 << s2 << '\n';
}
int main()
{
using namespace std::placeholders;
typedef std::function< void(string) > fn_t;
fn_t func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foo
Note that I defined a string object named "foo" instead of using string literals. The behavior is the same, so the problem is not related to this.
I think the problem comes from your typedef. The return of bind
(which is unspecified) is casted to a function taking a string
by value, while the wrapper returned by bind probably take its arguments by rvalue-reference and perfectly-forward them. Instead of using your own typedef, you should use the auto
keyword, so that the type of func
will be automatically deduced by the compiler. If we modify the main as follows, we obtain the expected behavior:
int main()
{
using namespace std::placeholders;
auto func = std::bind(print, _1, _1);
std::string foo("foo");
func(foo);
}
// outputs: foofoo
Another solution is to replace your typedef so that func
takes its parameter by reference-to-const:
typedef std::function< void(string const &) > fn_t;
I don't really understand why the other typedef does not work... Presumably the string is moved, as @ipc noted, but I don't know at what point of the execution this happens. I'm not even sure this is standard behavior, since both function
and the wrapper returned by bind
should use perfect forwarding. Perhaps GCC includes some optimizations that move the wrapper arguments when they are passed by value?
Edit
I did some tests, it turns out GCC's implementation of std::function
performs a move on its arguments, while the wrapper return by std::bind
does not. I still don't know if this is standard, I'm going to write a question about that.