返回类型 std::bind 隐式转换为两个不同的显式构造函数

return type of std::bind implicitly convertible to two different explicit constructors

本文关键字:两个 构造函数 bind std 转换 返回类型      更新时间:2023-10-16

给定两个explicit构造函数重载(基于不同的std::function<...>类型),std::bind的返回值能够选择其中之一(从而使调用变得模棱两可)

call of overloaded ‘Bar(std::_Bind_helper<false, void (Foo::*)(int), 
    Foo*, int>::type)’ is ambiguous

如果我注释掉任何一个,那么代码就会编译!

我本以为使构造函数explicit要么选择正确的重载,要么阻止两者被选中?

当然,在我绑定的点显式创建一个std::function是有效的:

    Bar b(std::function<void(int)>(std::bind((&Foo::process), &f, 1)));

但是,我很困惑为什么类型推断不起作用?

  • 如果来自 std::bind 的返回值与两个构造函数签名都不匹配,则它们explicit的事实应该会阻止选择这两个签名。
  • 如果来自 std::bind 的返回值与两个构造函数签名之一匹配,则explicit它们的事实应导致选择正确的构造函数签名。

这里到底发生了什么?

完整的工作代码如下:

#include <functional>
struct Foo
{
    void process(int) { }
};
struct Bar
{
    // comment out either of these to compile
    explicit Bar(std::function<void(int)>) {} 
    explicit Bar(std::function<void(short)>) {}
};
int main()
{
    Foo f;
    Bar b(std::bind(&Foo::process, &f, 1));
    return 0;
}

使构造函数explicit与参数必须完全匹配无关!显式构造函数的影响意味着它不会用于隐式转换不同类型的对象,该对象Bar使用此构造函数的类型。但是,如果您尝试使用直接初始化(即 Bar(x))初始化 Bar 对象,则将考虑这两个构造函数。

std::bind()的结果肯定不是std::function<Signature>,即它不完全匹配你的任何一个构造函数。由于std::function<Signature>有一个适用于函数对象的非explicit构造函数,因此两个签名确实匹配:生成的绑定表达式不需要任何参数,但它可以接受参数,即任何参数类型也不能用于区分Bar的两个构造函数中的哪一个应该匹配。即使绑定表达式需要一个参数,我认为它也不会用于偏爱一个构造函数而不是另一个构造函数。