“One Class-Type Conversion”规则引自c ++ Primer5th§7.5.4
仅允许一种类型转换
在第4.11.2节(第162页)中,我们注意到编译器将自动仅应用一个类类型转换。例如,以下代码出错,因为它隐式使用了两次转换:
//item.combine() need a parameter of class Sales_data,which has a constructor of string type;
item.combine("9-999-99999-9");
// error: requires two user-defined conversions:
// (1) convert "9-999-99999-9" to string
// (2) convert that (temporary) string to Sales_data
上述代码导致错误,因为它违反了“一类转换”的规则; 以下是Implicit conversions的介绍 基于上面的规则,我在学习c ++时遇到了两个问题,它们都是复制初始化,这意味着将调用复制构造函数。
string
考虑代码片段string a="hello";
,如果我们不考虑编译器经常进行某些优化的事实,例如 copy elision ,那么代码将被解释为:
"hello"
的类型从char[6]
转换为char*
; (转换1) string(char*)
的构造函数并生成临时string
对象temp
(转换为2) string(string&&)
的复制构造函数,最后得到a
问题好的,实际上 2转换会发生,为什么这不会违反“One Class-Type Conversion”规则?是因为从char[6]
到char*
的转换不是类型转换,因为char*
不是类型但是内置类型?
initializer_list
一旦我们使用vector
列表初始化
vector<int> example={1,2,3,4,5};
然后代码被解释为:
{1,2,3,4,5}
没有类似“hello”的类型,因此没有像char[6]
到char*
的转换{1,2,3,4,5}
转换为initializer_list<int> temp
的临时对象(转换1 )使用以下内容将initializer_list<int> temp
转换为vector<int> temp1
:( 转换2 )
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
vector( vector&& other );
的复制构造函数,最后得到vector<int> example
; 问题:哎呀!还有 2次转化!并且有 class-type 的所有转换!发生了什么事?
答案 0 :(得分:2)
好的,因为一个小时过去了,这里没有人回答这个问题,我自己也找到了答案。
共鸣是char[5]
到char*
不是类型转换,所以它不违反 One Class-Type Conversion 规则。
转化顺序
隐式转换序列按以下顺序组成:
1)零个或一个标准转换序列;
2)零或一个用户定义的转换;
3)零个或一个标准转换序列 在考虑构造函数或用户定义的转换函数的参数时,只允许一个标准转换序列(否则可以有效地链接用户定义的转换)。从一种内置类型转换为另一种内置类型时,只允许一个标准转换序列。
initializer_list
是一个特殊情况,实际上是 copy-list-initializaition 但不是 copy-initialization ,因此没有 2类型转换。见list initialization
- 否则,T的构造函数分两个阶段考虑:
检查将std :: initializer_list作为唯一参数的所有构造函数,或者作为第一个参数(如果其余参数具有默认值),并针对std ::类型的单个参数进行重载匹配。 initializer_list
因此,当我们使用initializer_list时,没有从其他转换为T ,这是 copy-constructor 的要求。见Copy initialization
如果T是类类型,并且其他类型的cv-nonqualified版本不是T或从T派生,或者如果T是非类型类型,但是其他类型是类类型,则用户 - 可以检查定义的转换序列,它们可以从类型的其他转换为T (或者从T派生的类型,如果T是类类型并且转换函数可用),并且通过以下方式选择最佳的转换序列超载分辨率。 转换的结果,这是一个prvalue临时(直到C ++ 17)prvalue表达式(自C ++ 17),如果使用转换构造函数,则用于直接初始化对象。最后一步通常是优化的,转换的结果直接在为目标对象分配的内存中构造,但是相应的构造函数(移动或复制)需要可访问,即使它不是用过的。 (直到C ++ 17)
所以带参数initializer_list<int>
的构造函数将被直接调用,但不会被move/copy
构造函数调用。虽然示例也没有违反 One Class-Type Conversion 规则。