为什么std::function可以隐式转换为参数更多的std::function?

Why does std::function can implicit convert to a std::function which has more parameter?

我有:

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;
}

我认为std::bind(print_str, str)的类型是std::function<void(std::shared_ptr<std::string>)>,但是上面的代码是正确的运行。 std::bind有什么技巧吗?

环境:centos, gcc82

std::bind所做的是正确的。它使用您提供的值 (str) 来调用 print_str。所以你不需要再指定它并且总是被绑定值替换。

#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;
}

输出:

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 不绑定任何值,但占位符和 returns 一个 int(int, int) 类函数

f2 绑定一个值和一个占位符,returns 一个 int(int) 类函数

f3 绑定两个值且没有占位符和 returns 一个 int() 类函数

f4 类似于 f2,只是占位符现在是第一个参数而不是第二个参数。

您的代码属于 f3 情况。

I think the type of std::bind(print_str, str) is std::function<void(std::shared_ptr<std::string>)>

不,std::bind(print_str, str) 的类型是未指定的函子类型,类似于

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

请注意,这可以使用任何参数或 none.

调用

您在这里遇到的是正确的,并且正是在做 std::bind 的设计目的。

简单来说: 它将采用 n 个参数的函数转换为采用 m 个参数的函数(其中 n >= m)。 在您的特定情况下,您给它一个带一个参数的函数并取回一个带零参数的函数。这个新函数将在内部调用 print_str 并始终将 str 作为参数传递。

旁注:

因为 C++11 中有 lambda,所以 std::bind 有点多余。 你所做的与此完全相同:

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;
}

希望这也有助于理解 std::bind 在幕后做了什么。