【问题标题】:How is ambiguity determined in the overload resolution algorithm?重载解决算法中的歧义是如何确定的?
【发布时间】:2015-03-17 03:12:09
【问题描述】:

我正在尝试理解重载解析方法。

为什么会这样模棱两可:

void func(double, int, int, double) {}
void func(int, double, double, double) {}

void main()
{
    func(1, 2, 3, 4);
}

但这不是?

void func(int, int, int, double) {}
void func(int, double, double, double) {}

void main()
{
    func(1, 2, 3, 4);
}

在第一种情况下,有 2 次完全匹配和 2 次转换,对应 1 次完全匹配和 3 次转换,在第二种情况下,有 3 次完全匹配和 1 次转换,对应 1 次完全匹配和 3 次转换。

那么为什么一个是模棱两可的而一个不是呢?这里的逻辑是什么?

【问题讨论】:

  • 有趣的边缘案例,但纯粹是学术性的。如果我看到它在生产代码中使用,有人会被解雇。
  • C++ ISO 可能会讲到这个。以后有人可以给我们参考。
  • @Blindy 跟他说话,是的。严肃地说,是的。但是解雇他?
  • @glglgl Blindy 瞎说
  • 用 Java 绘制连接:JLS 不会认为 2 次转换和 1 次转换有区别。它只会区分 have-to-convertnot-have-to-convertstackoverflow.com/questions/22991150/…

标签: c++ overload-resolution


【解决方案1】:

重载解析规则仅定义所有匹配集的部分顺序 - 如果重载 F1 不是比 F2 更好的匹配,它并不意味着 F2 比 @987654325 更好的匹配@。确切的偏序可以被认为是比较k 维度中的两个点,其中参数的数量是k。让我们在k-dim 空间-(x_1, x_2,..., x_k) < (y_1, y_2,..., y_k) if x_i <= y_i for all i and x_j < y_j for at least one j 中的点上定义这个偏序。这正是标准定义的候选非模板函数的偏序。

让我们看看你的例子:

void func(double, int,    int,    double) {}
                  vvv     vvv       vvv
                 better  better    equal
void func(int,    double, double, double) {}
          vvv                       vvv
         better                    equal

因此,严格来说,任何一个重载都不比另一个好。

在你的第二个例子中:

void func(int,   int,   int,   double) {}
          vvv    vvv    vvv     vvv
         equal  better better  equal
void func(int, double, double, double) {}
          vvv
         equal

现在,除了一个参数之外,第一个重载都比第二个好,并且永远不会比第二个差。因此,没有歧义 - 部分顺序确实表明第一个更好。

(以上描述未考虑函数模板,更多详情请见cppreference。)

【讨论】:

  • 我几乎可以肯定,部分排序的定义就像字典比较,所以如果f() 的第一个参数比g() 的第一个参数好,那么f() 比@“更好” 987654335@(否则看第二个等)。但似乎不是这样,很好的答案!
【解决方案2】:

标准中的措辞(§[over.match.best]/1)是:

[...] 让 ICSi(F) 表示将列表中的第 i 个参数转换为 类型的隐式转换序列>i-可行函数 F 的第一个参数。
[...] 如果对于所有参数 i,ICSi(F1) 不是更差,则一个可行函数 F1 被定义为比另一个可行函数 F2 更好的函数转换顺序比 ICSi(F2),然后
— 对于某些论点 j,ICSj(F1) 是比 ICSj(F2)

更好的转换序列

在您的第一种情况下,这两个函数未通过第一次测试。对于第一个参数,第一个函数(采用double)的转换顺序比第二个差。对于第二个参数,第二个函数的转换顺序比第一个更差(同样,int 在一种情况下必须提升为 double,但在另一种情况下则不能)。

因此,两个函数都没有通过第一条规则,并且调用是模棱两可的。

在第二对函数之间,第一个函数的每个参数至少具有与第二个函数匹配的参数一样好的转换。然后我们继续第二条规则,发现至少有一个参数(事实上是两个)第一个函数比第二个函数具有更好的转换(身份而不是提升)。

因此,第一个函数更匹配,将被选中。

【讨论】:

    【解决方案3】:

    模糊度由排名决定:

    1. 完全匹配:无需转换、左值到右值转换、限定转换、用户定义的类类型到同一类的转换
    2. 提升:积分提升、浮点提升
    3. 转换:整数转换、浮点转换、浮点整数转换、指针转换、指针到成员的转换、布尔转换、派生类到其基类的用户定义转换

    精确匹配获胜 vs 升级获胜 vs 转化。

    在示例中:

    void func(int, bool, float, int){cout << "int,bool,float,int" << endl;}
    void func(int, bool, int, int){cout << "int,int,int,int" << endl;}
    
    int main()
    {
        func(1,1,3.4,4);
    }
    

    参数 1(1) 在两者上都完全匹配
    参数 2(1) 在两者上都完全匹配
    参数 3(3.4) 可以转换为 float 和 int - Ambiguity 两者都不是更好
    参数 4(4) 在两者上都完全匹配

    但如果我们这样做:func(1,1,3.4f,4);
    (3.4f) 现在是完全匹配的!
    void func(int, bool, float, int) 然后赢得了这场战斗。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多