skip to Main Content

I have the following:

void print_str(std::shared_ptr<std::string> str) {
    std::cout << str->c_str() << std::endl;
}

int main() {
    auto str = std::make_shared<std::string>("Hello");
    std::function<void()> f = std::bind(print_str, str);

    f(); // correctly print: Hello

    return 0;
}

I think the type of std::bind(print_str, str) is std::function<void(std::shared_ptr<std::string>)>, but the code above is correctly running. Is there any trick in std::bind?

env: centos, gcc82

3

Answers


  1. What std::bind does is correct. It uses the value you provided (str) for the call to print_str. So you don’t need to specify it anymore and will always be replaced by the bound value.

    #include <iostream>
    #include <functional>
    
    int sum(int value1, int value2) {
        return value1 + value2;
    }
    
    int main() {
    
        std::function<int(int, int)> f1 = std::bind(sum, std::placeholders::_1, std::placeholders::_1);
        std::function<int(int)> f2 = std::bind(sum, 10, std::placeholders::_1);
        std::function<int()> f3 = std::bind(sum, 100, 200);
        std::function<int(int)> f4 = std::bind(sum, std::placeholders::_1, 200);
    
        int a = 1;
        int b = 2;
    
        std::cout << "the sum of " << a << " and " << b << " is: " << f1(a, b) << std::endl;
        std::cout << "the sum of " << 10 << " and " << b << " is: " << f2(b) << std::endl;
        std::cout << "the sum of " << 100 << " and " << 200 << " is: " << f3() << std::endl;
        std::cout << "the sum of " << 200 << " and " << b << " is: " << f4(b) << std::endl;
    
        return 0;
    }
    

    output:

    the sum of 1 and 2 is: 2
    the sum of 10 and 2 is: 12
    the sum of 100 and 200 is: 300
    the sum of 200 and 2 is: 202
    

    f1 binds no values but placeholders and returns an int(int, int) like function

    f2 binds one value and one placeholder and returns an int(int) like function

    f3 binds two values and no placeholder and returns an int() like function

    f4 is like f2 except that the place holder is now the first parameter instead of the second one.

    Your code falls into the f3 case.

    Login or Signup to reply.
  2. I think the type of std::bind(print_str, str) is std::function<void(std::shared_ptr<std::string>)>

    No, the type of std::bind(print_str, str) is an unspecified functor type, something like

    class binder
    {
        void(*f)(std::shared_ptr<std::string>);
        std::shared_ptr<std::string> p;
    public:
        template<typename... Args>
        void operator()(Args... ) { f(p); }
    };
    

    Note that this is callable with any arguments or none.

    Login or Signup to reply.
  3. What you are experiencing here is correct and is precisely doing what std::bind was designed for.

    Simply speaking:
    It turns a function taking n parameters into a function taking m parameters (where n >= m).
    In your particular case, you give it a function taking one parameter and get back a function taking zero parameters. This new function will internally call print_str and always pass str as argument.

    Side note:

    Since there are lambdas in C++11, std::bind is sort of redundant.
    What you are doing is exactly equivalent to this:

    void print_str(std::shared_ptr<std::string> str) {
        std::cout << str->c_str() << std::endl;
    }
    
    int main() {
        auto str = std::make_shared<std::string>("Hello");
        std::function<void()> f = [=]() { print_str(str); };
    
        f(); // correctly print: Hello
    
        return 0;
    }
    

    This hopefully also helps understanding what std::bind does behind the scenes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search