C++ Function bind repeating arguments to curried function

别说谁变了你拦得住时间么 提交于 2019-12-01 16:58:19

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!