考虑以下C ++代码:
struct B { };
struct A
{
A(int);
A(A&); // missing const is intentional
A(B);
operator B();
};
A f()
{
// return A(1); // compiles fine
return 1; // doesn't compile
}
这在MSVC ++ 2010上编译得很好(实际上,在MSVC上,如果我完全删除B
,它甚至可以工作)。它不在GCC 4.6.0上:
conv.cpp: In function ‘A f()’:
conv.cpp:13:9: error: no matching function for call to ‘A::A(A)’
conv.cpp:13:9: note: candidates are:
conv.cpp:6:2: note: A::A(B)
conv.cpp:6:2: note: no known conversion for argument 1 from ‘A’ to ‘B’
conv.cpp:5:2: note: A::A(A&)
conv.cpp:5:2: note: no known conversion for argument 1 from ‘A’ to ‘A&’
conv.cpp:4:2: note: A::A(int)
conv.cpp:4:2: note: no known conversion for argument 1 from ‘A’ to ‘int’
令我困惑的是消息no known conversion for argument 1 from ‘A’ to ‘B’
。考虑到A::operator B()
定义得非常明确,这怎么可能呢?
答案 0 :(得分:5)
因为你不能做多个隐式转换。你必须去A::A(A::A(int)::operator B())
才能完成这项工作,这对于编译器来说有太多的步骤可以解决它自己的问题。
答案 1 :(得分:5)
我认为,正如DeadMG所指出的那样“过多地自行计算”是其原因。我有3-4次转换的构造,编译器总是把它们搞得很好。
我认为问题在于不允许编译器代表自己将const
引用转换为非const
引用(只有在明确告知时才允许这样做)它与演员)
由于对传递给复制构造函数的临时对象的引用是const
,但复制构造函数不是,它找不到合适的函数。
编辑:我没有找到任何“真实”代码(请参阅下面的评论),但构建了一个多zigzag转换示例,实际上在gcc 4.5下编译时没有错误。请注意,这也与-Wall -Wextra
编译得很好,这让我很惊讶。
struct B
{
signed int v;
B(unsigned short in) : v(in){}
};
struct C
{
char v;
C(int in) : v(in){}
};
struct A
{
int v;
A(B const& in) : v(in.v){}
operator C() { return C(*this); }
};
enum X{ x = 1 };
int main()
{
C c = A(x);
return 0;
}
答案 2 :(得分:4)
被拒绝的候选人名单上的错误非常清楚。问题是涉及用户定义的C ++语言转换的隐式转换序列仅限于单个用户定义的转换:
§13.3.3.1.2[over.ics.user] / 1用户定义的转换序列包括初始标准转换序列,后跟用户定义的转换(12.3),然后是第二个标准转换序列。 / p>
标准转换序列在§4[conv]:
中定义[...]标准转换序列是一系列标准转换,按以下顺序
来自以下集合的零或一次转换:左值到右值的转换,数组到指针的转换以及函数到指针的转换。
来自以下设置的零次或一次转换:整数促销,浮点促销,积分转换,浮点转换,浮点积分转换,指针转换,指向成员转换的指针以及布尔转换。
零或一个资格转换。
问题在于,您的代码无法通过应用单个用户定义的转换从a)int
rvalue转到b)B
。
特别是,所有可用的转换序列都以用户定义的转换(隐式构造函数A(int)
)开头,产生A
rvalue。从那里,rvalue不能绑定到非const引用来调用A::A( A& )
,因此该路径被丢弃。所有其他路径都需要第二个用户定义的转换是不允许的,事实上,唯一能让我们指向b)的其他路径需要另外两个用户定义的转换,总共3个。
答案 3 :(得分:0)
错误列出了要使用的所有潜在候选项,以及无法使用它们的原因。它列出了B
的转换,因为它是构造函数之一,但在这种情况下它不知道如何使用它,所以它没有。