如何在重载决策算法中确定歧义?

Ana*_*a M 61 c++ overload-resolution

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

为什么这个含糊不清:

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

void main()
{
    func(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)

但这不是?

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

void main()
{
    func(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,有2个精确参数匹配,2个转换针对1个完全匹配和3个转换,在第二种情况下,有3个完全匹配,1个转换针对1个完全匹配和3个转换.

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

Pra*_*han 54

重载决策规则仅定义所有匹配集合的部分顺序 - 如果重载F1不是一个更好的匹配F2,它并不意味着它F2是一个更好的匹配F1.确切的偏序可以被认为是比较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
Run Code Online (Sandbox Code Playgroud)

因此,任何过载都不会严格地优于其他过载.

在你的第二个例子中:

void func(int,   int,   int,   double) {}
          vvv    vvv    vvv     vvv
         equal  better better  equal
void func(int, double, double, double) {}
          vvv
         equal
Run Code Online (Sandbox Code Playgroud)

现在,除了一个参数之外,第一个重载优于第二个,并且永远不会比第二个更糟.因此,没有歧义 - 部分顺序的确确认为第一个更好.

(以上描述不考虑功能模板.您可以在cppreference上找到更多详细信息.)


Jer*_*fin 13

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

[...]让ICS (F)表示该转换的隐式转换序列在列表中第一个参数的类型可行函数的第参数F.
[...]的可行功能F1是如果对于所有参数i,ICS i(F1)不是比ICS i(F2)更差的转换序列,则定义为比另一个可行函数F2更好的函数,然后
- 对于某些参数j,ICS j(F1)是转换序列比ICS j(F2)更好

在第一种情况下,这两个函数在第一次测试时失败.对于第一个参数,第一个函数(take double)的转换序列比第二个函数更差.对于第二个参数,第二个函数的转换序列比第一个更差(同样,int必须double在一种情况下提升到另一种情况,而不是另一种情况).

因此,两个函数都没有通过第一个规则,并且调用是不明确的.

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

因此,第一个功能是更好的匹配,并将被选中.