【问题标题】:conversion precedence in c++c++中的转换优先级
【发布时间】:2009-07-07 14:35:48
【问题描述】:

我有以下代码:

Some functions:

A::A(int i_a) {cout<<"int Ctor\n";}          //conversion constructor

void h(double d) {cout<<"double param\n";}   //f1
void h(A a) {cout<<"A param\n";}             //f2

在主函数中:

h(1);

h(1) 调用的函数是 f1。

我的问题是它为什么选择这样称呼它。 1 是一个 int,因此需要 隐式转换为双精度。它可以很容易地将 int 转换为 A 使用 上面定义的转换构造函数。为什么我没有收到错误消息?什么是 强制转换的优先规则?


注意我已经在上面发布了我认为有必要回答这个问题的代码, 但下面我发布了整个代码:

 #include <iostream>
 using namespace std;
 class B;
 class A {
 public:
 explicit A(const B&) {cout<<"Ctor through B\n";}
 A() {cout<<"Default Ctor\n";}
 A(int i_a) {cout<<"int Ctor\n";}
 operator int() {cout<<"A => int\n"; return 2;}
 };
 class B {
 public:
 operator A() const {cout<<"B => A\n"; A a; return a;}
 };
 void h(double d) {cout<<"double param\n";}
 void h(A a) {cout<<"A param\n";}
 void f(const A& a)
 {
 cout<<"f function\n";
 //Without the const it will never try to convert
 }
 void main()
 {
 B b;
 cout <<"-----------------\n";
 f(b);
 cout <<"-----------------\n";
 h(1);
 }

【问题讨论】:

  • 发布代码时。不要添加行号 - 如果不进行额外编辑,就无法编译它。如果您想突出显示行号,请使用注释。
  • 编辑的行号输出。
  • 作为旁注,我不会将“A::A(int i_a)”称为转换构造函数,只是 A 的构造函数,它恰好将 int 作为参数。此外,使用其确切参数调用 h(任何 h)总是好的。如果它需要一个 A(第二个函数),那么为什么不给它一个 A 呢?例如 h(A(1));
  • @Daniel- 我试图更好地理解 c++ 是如何工作的。显然上面的代码并不是最优的。
  • @Daniel: "A::A(int i_a)" 被称为转换构造函数,因为它会将整数隐式转换为 A 对象。如果您在 ctor 定义前添加关键字“explicit”,则此隐式转换行为将被删除——然后,它“只是”A 的构造函数,恰好将 int 作为参数。

标签: c++


【解决方案1】:

当执行重载决策以从所有可行的重载中选择最佳候选时 - 编译器对每个候选的每个参数的所有转换序列进行排名。对于获胜的函数(被选为最佳候选者),它的每个参数的转换等级必须优于或等于该参数的每个其他函数的转换等级,并且至少一个转换等级必须优于所有其他函数对某个参数的转换等级。

用户定义的转换(使用构造函数或强制转换运算符)具有最差的等级之一(只有省略号具有更差的等级)。积分浮动转换的排名更高(请参阅下面的排名列表)。

因此,编译器更喜欢转换 int -> double(使用标准转换)而不是转换 int -> A(使用用户定义的转换),因此它选择 f1。

编辑:虽然“重载解决方案”在后台运行,并且大多数时候都完全符合您的预期(即大多数程序员不需要深入研究技术细节) - 如果您确实想更深入(但要警告说,重载决议的一些较暗的角落被认为是编译器编写者在 C++ 编译器中完全正确的最棘手的方面之一)参考优秀的 C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis,它在附录 B 中提供了最好的介绍之一我读过的重载决议背后的机制。

这是 B.2 的摘录:

重载解决方案排名可行 通过比较候选函数 调用的每个参数都匹配 对应的参数 候选人。对于一名候选人 被认为比另一个更好, 更好的候选人不能有任何 它的参数比 中对应的参数 其他候选人。 ...

鉴于第一个原则,我们是 剩下指定给定的 参数匹配相应的 可行候选人的参数。作为一个 我们可以对第一个近似值进行排名 可能的匹配如下(从最好的 最差):

完美匹配。该参数具有 表达式的类型,或者它有一个 type 是对该类型的引用 表达式的(可能加上 const 和/或 volatile 限定符)。

配合微调。这 包括,例如,一个衰变 数组变量指向它的指针 第一个元素,或添加 const 匹配类型的参数 int** 到 int 类型的参数 常量* 常量*。

与促销相匹配。促销是一种 一种隐式转换 包括小转换 整数类型(例如 bool、char、 简短,有时是枚举)到 int, unsigned int, long 或 unsigned 长,并将浮点数转换为 双倍。

仅与标准转换匹配。 这包括任何类型的标准 转换(例如 int 到 float)但是 排除对 a 的隐式调用 转换运算符或转换 构造函数。

匹配用户定义的转换。 这允许任何类型的隐式 转换。

匹配省略号。省略号 参数几乎可以匹配任何类型 (但非 POD 类类型会导致 未定义的行为)。

但这只是开始 - 如果你感兴趣 - 我敦促你阅读这本书,然后阅读标准的相关部分 :)

【讨论】:

    【解决方案2】:

    从标准中添加(N4687)

    2

    在比较隐式转换序列的基本形式时(如 在 16.3.3.1 中定义)

    ——(2.1) 标准转换序列 (16.3.3.1.1) 是比用户定义的更好的转换序列 转换序列或省略号转换序列,以及

    — (2.2) 一个 用户定义的转换序列(16.3.3.1.2)是更好的转换 序列比省略号转换序列(16.3.3.1.3)。

    【讨论】:

      猜你喜欢
      • 2012-04-13
      • 2014-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 2011-03-22
      • 1970-01-01
      相关资源
      最近更新 更多