在继续阅读本文之前,请首先阅读Is there a difference in C++ between copy initialization and direct initialization?,确保你明白它在说什么。C++复制初始化和直接初始化,奇怪的情况
我会在这里先总结一下规则(读取标准n3225 8.5/16,13.3.1.3,13.3.1.4和13.3.1.5),
1)直接初始化,所有构造函数都会被视为重载设置,重载分辨率将根据重载解析规则选择最佳分辨率。
2)对于复制初始化和源类型与目标类型相同或从目标类型派生,除了仅将转换构造函数(构造函数没有显式)视为重载集外,其规则与上述相同。这实际上意味着显式复制/移动构造函数不会被视为重载集合。 3)对于上面(2)中未包括的复制初始化情况(源类型与目标类型不同并且不是源自目标类型),我们首先考虑用户定义的转换序列,其可以从源类型转换为目标类型或(当使用转换函数时)到其派生类。如果转换成功,则结果用于直接初始化的目标对象。在本用户定义的转换序列中,根据8.5/16和13.3.1.4中的规则,将考虑转换ctors(非显式ctors)和非显式转换函数。
3.2)结果prvalue将直接初始化为目标对象,如(1)中列出的规则,参见8.5/16。
好的,对规则来说足够了,让我们看看一些奇怪的代码,我真的不知道我的推理是错误的,还是只是所有的编译器都是错误的。请帮助我,谢谢。
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
struct B
{
operator A() { return 2; }
//1) visual c++ and clang passes this
//gcc 4.4.3 denies this, says no viable constructor available
};
int main()
{
B b;
A a = b;
//2) oops, all compilers deny this
}
在我的理解,对于(1),
operator A() { return 2; }
因为C++具有函数返回被作为复制初始化,根据上述规则的规则,2将被首先隐式转换到A,这应该是确定的,因为A有一个构造函数A(int)。然后,转换后的临时值将被用来直接初始化返回的对象,这应该也可以,因为直接初始化可以使用显式拷贝构造函数。所以GCC是错误的。
对于(2),
A a = b;
在我的理解,首先b为隐式转换为A,由运营商A(),然后将转换后的值将用于直接初始化,这可当然要调用显式拷贝构造函数?因此,这应该通过编译和所有编译器都是错误的?请注意,对于(2),visual C++和clang都有类似于 的错误“错误,无法从B转换为A”,但如果我在A的复制构造函数中删除显式关键字,则错误不见了..
感谢您的阅读。
编辑1
因为有人还是没有得到我的意思,我引述8.5/16以下的标准,
否则(即,对剩余的 复印通初始化情况), 用户定义的转换序列 可以从源类型转换为 目标类型或(当使用 转换功能时)转换为 的派生类如13.3.1.4中所述列举为 ,并且最好的 通过分解(13.3)的过载 来选择。如果转换 无法完成或不明确,则 初始化格式不正确。使用 初始化程序表达式作为其参数 调用所选的 函数;如果该函数是构造函数 ,则该调用将初始化 暂时的目标类型的cv未合格版本 版本。 临时是一个prvalue。的 呼叫的结果(这是临时用于 构造情况下)随后被用于 直接初始化,根据上述规则 ,那是 目的地的 复制初始化的对象。在某些情况下, 的执行被允许为 通过构造 直接初始化对象的 直接初始化来消除此 直接初始化中固有的复制;见 12.2,12.8。
请注意,它确实提到在用户定义的转换后直接初始化。这意味着,根据我的理解,以下代码应遵守规则,正如我所评论的,这是由clang,coomeau online,visual C++所证实的,但GCC 4.4.3不能同时满足(1)和(2)的要求。虽然这是一个奇怪的规则,但它遵循标准的推理。
struct A
{
A (int) { }
A() { }
explicit A(const A&) { }
};
int main()
{
A a = 2; //1)OK, first convert, then direct-initialize
A a = (A)2; //2)oops, constructor explicit, not viable here!
}
Comeau Online以书面形式接受整个代码片段。 –
好的,谢谢。这给了我一些信心,我的推理至少不会走向错误的方向。^_^ – user534498
@詹姆斯麦克奈利斯:然而,科莫在线拒绝我的答案中的代码,尽管根据OP的推理它应该被接受。 – AnT