转换优先级在c ++ [英] conversion precedence in c++

查看:201
本文介绍了转换优先级在c ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

 一些函数:

A :: A i_a){cout<<int Ctor\\\
;} //转换构造函数

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

在主函数中:

  h 

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



我的问题是为什么它选择调用它。 1是一个int,因此需要
隐式转换为double。它可以像使用上面定义的
转换构造函数一样轻松地将int转换为A.为什么我不会收到错误?
的优先级规则是什么?






我发布上面的代码,我认为必要的回答问题,
,但下面我发布整个代码:

  #include< iostream> 
using namespace std;
class B;
class A {
public:
explicit A(const B&){cout<<Ctor through B \\\
;}
A(){cout< ;Default Ctor\\\
;}
A(int i_a){cout ;}
operator int(){cout< ; int\\\
; return 2;}
};
class B {
public:
operator A()const {cout<<B => A\\\
; A a; return a;}
};
void h(double d){cout<<double param\\\
;}
void h(A a){cout<<A param\\\
;}
void f(const A& a)
{
cout<<f function\\\
;
//没有const它永远不会尝试转换
}
void main()
{
B b;
cout<<----------------- \\\
;
f(b);
cout<<----------------- \\\
;
h(1);
}


解决方案

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



用户定义的转换(使用构造函数或转换操作符)具有最差的排名之一(只有省略号更差的排名)。



因此,编译器优先转换int - > double(使用标准转换)比转换int - > A(使用用户定义的转换),因此它选择f1。



编辑:虽然过载分辨率大多数时间确实是你所期望的(即大多数程序员不需要深入到技术层面) - 如果你想更深入(但是警告,一些较深的角落的过载分辨率被认为是一个的编译器作者在C ++编译器中获得完全正确的最棘手的方面)指的是优秀的
C ++模板:David Vandevoorde和Nicolai M. Josuttis的完整指南
,它在附录B中提供了我已经阅读的关于重载解决机制的最好的介绍之一。



以下是B.2的摘录:


过载解析可行的
候选函数,通过比较调用的每个参数

候选的
对应参数相匹配。对于一个候选人是
被认为比另一个更好,
更好的候选人不能具有任何
其参数比
更糟的匹配
其他的相应参数候选人。
...



根据这第一个原则,我们留下
,指定给定的
参数与对应的
可行候选者的参数。作为
第一近似,我们可以将
可能的匹配排序如下(从最好的
到最差):



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



与小调整匹配。这个
包括例如
数组变量到指向其
第一元素的指针的衰减,或者添加
const以匹配类型$ b $的参数b int **到类型为int
const * const *的参数。



与促销匹配。促销是一种
种隐式转换,
包括将小的
整数类型(例如bool,char,
short,有时是枚举)转换为
int ,unsigned int,long或unsigned
long,并将float转换为
double。



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

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



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



b $ b

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


I have the following code:

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

In the main function:

h(1);

The function that h(1) calls is f1.

My question is why does it choose to call that. 1 is an int and therefore requires implicit conversion to double. It could just as easily convert the int into an A using the conversion constructor defined above. Why don't I get an error? What are the precedence rules with casting?


N.b. I've posted above the code that I think will be necessary to answer the question, but below I'm posting the entire code:

 #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);
 }

解决方案

When overload resolution is performed to select the best candidate out of all viable overloads - the compiler ranks all the conversion sequences for each argument for each candidate. For a function to win (be selected as the best candidate), its conversion ranks for each argument have to be better than or equal to every other function's conversion ranks for that argument AND at least one conversion rank has to be better than all the other function's conversion ranks for a certain argument.

The user defined conversion (which uses either a constructor or a cast operator) has one of the worst possible ranks (only the ellipsis has a worse rank). The integral-floating conversion has a better rank (see below for a list of the rankings).

Thus, the compiler prefers converting an int -> double (using a standard conversion) than converting an int -> A (using a user defined conversion), and therefore it selects f1.

Edit: Although "Overload resolution" works in the background and most of the time does exactly what you would expect (i.e. most programmers won't need to delve into the technicalities) - if you do want to go deeper (but be warned that some of the darker corners of overload resolution are considered to be one of the trickiest aspects for compiler writers to get exactly right in a C++ compiler) refer to the excellent C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis which provides, in appendix B, one of the best introductions to the machinery behind overload resolution that I have read.

Here is an excerpt from B.2:

Overload resolution ranks the viable candidate functions by comparing how each argument of the call matches the corresponding parameter of the candidates. For one candidate to be considered better than another, the better candidate cannot have any of its parameters be a worse match than the corresponding parameter in the other candidate. ...

Given this first principle, we are left with specifying how well a given argument matches the corresponding parameter of a viable candidate. As a first approximation we can rank the possible matches as follows (from best to worst):

Perfect match. The parameter has the type of the expression, or it has a type that is a reference to the type of the expression (possibly with added const and/or volatile qualifiers).

Match with minor adjustments. This includes, for example, the decay of an array variable to a pointer to its first element, or the addition of const to match an argument of type int** to a parameter of type int const* const*.

Match with promotion. Promotion is a kind of implicit conversion that includes the conversion of small integral types (such as bool, char, short, and sometimes enumerations) to int, unsigned int, long or unsigned long, and the conversion of float to double.

Match with standard conversions only. This includes any sort of standard conversion (such as int to float) but excludes the implicit call to a conversion operator or a converting constructor.

Match with user-defined conversions. This allows any kind of implicit conversion.

Match with ellipsis. An ellipsis parameter can match almost any type (but non-POD class types result in undefined behavior).

But that's just the beginning - if you are intrigued - I urge you to read the book and then the relevant portions of the standard :)

这篇关于转换优先级在c ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆