如何确定两个优先于重载解析的隐式转换序列?
Posted
技术标签:
【中文标题】如何确定两个优先于重载解析的隐式转换序列?【英文标题】:How to determine two implicit conversion sequences preferred than each other for overload resolution? 【发布时间】:2021-12-25 12:43:28 【问题描述】:我想对伴随隐式类型转换的重载决议提出疑问。这个问题参考cppreference 1和2。
似乎一个隐式转换序列最多只有三个步骤才能将类型T1
(参数类型)转换为T2
(参数类型):
-
零个或一个标准转换序列;
隐式转换序列可以归类为以下之一:
标准转换序列(我只对这种基本类型转换情况感兴趣。)并且,每种类型的标准转换序列都被分配了三个等级之一:
-
完全匹配:无需转换,左值到右值转换,限定转换,函数指针转换,类类型到同一个类的自定义转换
推广:积分推广、浮点推广
转换:整数转换、浮点转换、浮点整数转换、指针转换、指针到成员的转换、布尔转换、派生类到其基类的用户定义转换
还有,
标准转换序列的排名是它所拥有的标准转换排名中最差的。
我认为会有这样一种情况,两个隐式转换序列的组成标准转换序列步骤彼此具有不同的等级。所以,恕我直言,我很难确定哪个隐式转换序列比另一个更受欢迎。
例如(不幸的是,我想不出一个具体的例子。),
一个隐式转换序列(A)由
组成-
标准转换顺序(A-1),即排名提升。
没有用户定义的转换顺序
标准转换序列(A-2),即等级conversion。
另一个隐式转换序列(B)由
组成-
标准转换序列(B-1),即等级conversion。
没有用户定义的转换顺序
标准转换顺序(B-2),即排名提升。
在这种情况下,A-1 优于 B-1,但 B-2 优于 A-2 。因此,A 和 B 中的每一个都有自己的偏好。 -> 模棱两可的电话?
OR... A-1 和 B-1 应该首先比较 A-2 和 B-2 。那么,我们是否应该停止在这里进行贪婪比较呢? -> A 被选中了吗?
更新:解释我对这些概念的理解......
// [ what is overall rank for standard coversion sequence n ]
// [ standard conversion sequence n(up to 2) ]
// [ each conversion's rank in a std conv sequence n ]
// [ what conversions are performed in a std conv sequence n ]
// [ how source type T1 is converted to target type T2 ]
// [ promotion ][ exact match ]
// [ std conv seq1 ][ std conv seq2 ]
// [ promotion | exact match ][ exact match ]
// [ promotion | const qualification ][ no conversion ]
// [char -> int -> const int -> const int ]
void f(const int)
std::cout << "f(const int)" << std::endl;
// [ promotion ][ conversion ]
// [ std conv seq1 ][ std conv seq2 ]
// [ promotion || conversion | exact match ]
// [ promotion || integral conversion, const qualification ]
// [char -> int -> long -> const long ]
void f(const long)
std::cout << "f(const long)" << std::endl;
int main()
// For the first sequence, the two functions have same 2nd rank, 'promotion'.
// So, we couldn't determine which function will be called yet.
// But, for the second sequence, the former has 1st rank 'exact match'
// and the latter has 3rd rank 'conversion'. So the former will be called.
f('c'); // prints "f(const int)"
【问题讨论】:
如果 A-1 完全匹配,那么 A-2 怎么会不完全匹配?转换要么是完全匹配,要么需要对类型进行一些转换。不能两者都。 这里与 A 和 B 的比较,是指一个函数的两个不同重载,其中参数可以以两种不同的方式转换,还是指一个具有两个参数的函数,每个参数都有不同的转化? @super 对于一个函数调用,存在两个可行的重载函数(在您的评论中,前一种情况)。每个函数都涉及其自己的隐式转换。为简单起见,该函数只有一个参数。 @NicolBolas 术语精确匹配不是用来指定最佳可行函数。它用于隐式转换的等级。请参考Ranking_of_implicit_conversion_sequences @rosshjb:但术语“精确匹配”表示源类型和目标类型之间的关系。如果 A-1 是“完全匹配”,则意味着源类型和目标类型相同。那么怎么会有后来的转化匹配呢? 【参考方案1】:Cppreference 是一个有用的参考站点,但它不是 C++ 标准。它包含大部分准确的信息,但在简化标准的复杂性时,可能会丢失一些细节。
我将引用 C++17(因为我没有可以链接到的 C++11 网站),但措辞没有有意义的改变。
[over.best.ics]/3defines an implicit conversion sequence as:
格式良好的隐式转换序列是以下形式之一:
标准转换序列, 用户定义的转换序列,或 省略号转换序列。
这或多或少是 Cppreference 所说的,但在这里更明确的是,您要么拥有精确的 一个 标准转换序列,要么拥有精确的 一个 用户-定义的转换。用户自定义转换本身 includes two standard conversion sequences:
用户定义的转换序列由初始标准转换序列和用户定义的转换 ([class.conv]) 以及第二个标准转换序列组成。
Cppreference 使您看起来可以有两个标准的转换序列没有用户定义的转换,但你不能。如果没有用户定义的转换在起作用,那么您只有一个标准转换。
不要试图将 Cppreference 解读为 C++ 的合法定义。更多地把它想象成“C++ 主要是这样工作的”。如果您需要法律细节(在大多数情况下,您不需要。特别是关于重载解决方案。对此了解太多可能会使您成为一个糟糕的程序员),那么您必须达到标准。
【讨论】:
谢谢。正如你所说,我可以同意隐式转换序列。特别是If there is no user-defined conversion in play, you have only one standard conversion.
我有一个问题。根据您的回答,应该如何处理f('c')
到void f(long)
的呼叫? char
到 long
的转换是积分促销还是积分转换?根据您的回答,char
不能先升级为int
,因为int
应再次转换为long
。正如你所说,std conv seq只有一个,转换和提升不能同时发生在一个序列中。
@rosshjb: "转换和提升不能在一个序列中发生。" 从char
到long
的转换是一个完整的转换。没有“升级到int
”。此外,您不应该在对用户完全重要的地方编写代码。
a standard conversion sequence is either the Identity conversion by itself (that is, no conversion) or consists of one to three conversions from the other four categories. At most one conversion from each category is allowed in a single standard conversion sequence.
— over.ics.scs/3。 A conversion from char to long is an integral conversion.
是否意味着f('c')
会通过将char
积分转换为long
来调用void f(long)
?
@rosshjb:那你的问题是什么? char
升级为 int
,然后转换为 long
。再说一次,为什么重要?这种卖弄细节的方式能给你带来什么?您可以将char
传递给任何采用大多数整数类型的函数。这就是你需要知道的。
我评论了错误的链接。正确的链接是here 和here。后一个链接中的(1.2)表示积分促销和积分转换不能同时发生。但前一个链接说,两者可以同时发生。很奇怪。以上是关于如何确定两个优先于重载解析的隐式转换序列?的主要内容,如果未能解决你的问题,请参考以下文章