【问题标题】:Why Overload resolution is unable to decide which version of an overloaded function to initialize an std::function object?为什么重载决议无法决定哪个版本的重载函数来初始化 std::function 对象?
【发布时间】:2020-05-03 16:05:21
【问题描述】:

我有这个关于std::function的例子:

int add(int x, int y, int z) {return x + y + z;}
int add(int a, int b) {return a + b;}

int main()
{
    std::function<int(int, int)> fn = add; // error

    int(*pfn)(int, int) = add; // OK
    fn = pfn; // ok  fn is bound to add(int, int)
    std::cout << fn(5, 7) << std::endl; // 12

}
  • 为什么在初始化fn时重载解析无法解析add的哪个版本,但能够初始化函数指针pfn

  • 是否有一种解决方法,而不是使用函数指针来决定哪个版本的重载函数作为 std::function 对象的初始化程序?

【问题讨论】:

  • std::function 有一个模板化的构造函数,它几乎可以接受任何东西。编译器没有信号来选择正确的重载。一种可能的解决方法是显式转换:std::function&lt;int(int, int)&gt; fn = static_cast&lt;int(*)(int, int)&gt;(add);
  • @IgorTandetnik:是的,我认为在这里使用static_cast 是个好主意,谢谢。

标签: c++ function function-pointers overload-resolution


【解决方案1】:

为什么在初始化fn时重载解析不能解析add的哪个版本,但能够初始化函数指针pfn

因为overload resolution是在初始化函数指针(如pfn)时,根据函数指针的类型进行的。

在所有这些上下文中,从重载集中选择的函数是其类型与 target 期望的函数指针、函数引用或成员函数类型的指针匹配的函数:正在初始化的对象或引用、赋值的左侧、函数或运算符参数、函数的返回类型、强制转换的目标类型或模板参数的类型。

另一方面,在初始化std::function 时不会发生这种重载决议,它有一个构造函数模板,模板参数需要从函数参数中推导出来;编译器无法选择一个进行推导。

作为解决方法,您可以应用static_cast 来明确指定您想要的重载。

static_cast 也可用于通过将函数到指针转换为特定类型来消除函数重载的歧义

std::function<int(int, int)> fn = static_cast<int(*)(int, int)>(add);

【讨论】:

    【解决方案2】:

    对于函数指针的情况,C++ 有一个特殊的规则允许一种“时间旅行”查找。它可以根据您要分配/初始化名称的内容对名称执行重载解析。

    这基本上是语言内置的 hack([over.over] 中的规则)。

    该语言的任何其他部分都不会以这种方式工作。例如,新手通常期望在编写float x = 1/2x 的值将是0.5,我们必须解释您正在初始化float 的事实与类型或计算无关表达式1/2

    此 hack 未扩展到 std::function。大概是因为添加 hack 是不好的,并且因为这种情况不需要它。为什么不?因为您仍然可以在 std::function 初始化的 RHS 上使用 static_cast 间接部署黑客:

    std::function<int(int, int)> fn = static_cast<int(*)(int, int)>(add);
    

    ……这就是你的解决方法。

    【讨论】:

    • 你为什么称它为“黑客”而不是“功能”?
    • @Maestro "Hack" 是 "feature" 的子集。当一个功能使用在周围环境中其他地方没有的习语或惯例时,我认为它是一种 hack,并且在某些方面与其他地方的现有惯例相反。这样的事情是一种黑客行为,因为为了提供该功能似乎必须违反既定的设计圣经,因此必须破例。我不认为这是对这个词的不寻常用法。
    猜你喜欢
    • 2020-04-07
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 2014-11-11
    相关资源
    最近更新 更多