【问题标题】:Why does std::function can implicit convert to a std::function which has more parameter?为什么 std::function 可以隐式转换为具有更多参数的 std::function?
【发布时间】:2020-10-28 18:24:33
【问题描述】:

我有以下:

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&lt;void(std::shared_ptr&lt;std::string&gt;)&gt;,但上面的代码运行正常。 std::bind有什么技巧吗?

环境:centos、gcc82

【问题讨论】:

  • 不,这不是std::bind(print_str, str) 的类型。毕竟生成的函数没有参数,原函数的唯一参数已经绑定,那么第二个参数从哪里来?

标签: c++ c++11 std-function stdbind


【解决方案1】:

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 不绑定任何值,只绑定占位符,并返回类似 int(int, int) 的函数

f2 绑定一个值和一个占位符并返回一个int(int) 类似函数

f3 绑定两个值且没有占位符并返回一个int() 类似函数

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

您的代码属于f3 情况。

【讨论】:

  • 感谢您的回答!这很容易理解。运行您的代码后,我的另一个任务是,为什么 std::function&lt;int(int,int)&gt; f5 = std::bind(sum, 1, 2); 编译正确?换句话说,auto f = std::bind(sum, 1, 2);中f的推断类型是什么?
  • stl 没有指定 std::bind 的返回类型。 auto f 具有仿函数类型,您可以传递任意数量的参数,但至少可以传递绑定指定的占位符数量。其他参数将不会被使用
  • @Griyn 这是一个相当有趣的观察。你应该要求那个而不是你实际要求的 ;-) 看起来 std::bind 有一些不可预测的“功能”:stackoverflow.com/q/40547846/9883438
  • @sebrockm 谢谢!也有助于解决我的困惑。
【解决方案2】:

我认为std::bind(print_str, str) 的类型是std::function&lt;void(std::shared_ptr&lt;std::string&gt;)&gt;

不,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); }
};

请注意,这可以使用任何参数或无参数调用。

【讨论】:

    【解决方案3】:

    您在此处遇到的情况是正确的,并且完全符合 std::bind 的设计目的。

    简单来说: 它将采用n 参数的函数转换为采用m 参数的函数(其中n &gt;= 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 在幕后所做的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-12
      • 2012-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-11
      • 2014-03-02
      • 2015-05-23
      相关资源
      最近更新 更多