struct A {};
struct B
{
B (A* pA) {}
B& operator = (A* pA) { return *this; }
};
template<typename T>
struct Wrap
{
T *x;
operator T* () { return x; }
};
int main ()
{
Wrap<A> a;
B oB = a; // error: conversion from ‘Wrap<A>’ to non-scalar type ‘B’ requested
oB = a; // ok
}
构建oB
后,为B::B(A*)
调用了为什么Wrap<T>::operator T ()
? [注意:在下一个语句中为B::operator = (A*)
调用Wrap<T>::operator T ()
答案 0 :(得分:10)
问题在于隐式调用的用户定义转换的数量受标准限制(为1)。
B ob = a;
意味着两次用户转换:
a
:Wrap<A>::operator A*()
应该被称为B::B(A*)
应该被称为 @James Kanze的解释:这种语法称为“复制初始化”,实际上相当于B ob = B(a)
(大部分时间都删除了副本)。这与B ob(a)
不同,B ob = B(a);
是“直接初始化”并且可以有效。
如果您明确限定其中的任何一项,它将起作用,例如:
ob = a;
另一方面,对于第二种情况,没有问题:
ob.operator=(a);
是简称:
{{1}}
因此只需要一个用户定义的转换,这是允许的。
修改强>:
由于评论中需要(对基里尔的回答),我们可以猜测一下动机。
链式转换可能很长很长,因此:
此外,只要转换次数超过1次,就会遇到必须检测到周期的风险(即使可能不需要诊断,并且要遵守实施质量)。< / p>
所以,因为有必要限制以避免无限长的搜索(它可能未被指定,需要最低限度),并且由于超过1我们可能有新的问题(周期),那么1似乎是一个很好的限制毕竟。
答案 1 :(得分:7)
这是因为你正在使用“复制初始化”。如果你写的
声明oB
:
B oB(a);
,它应该工作。两个初始化的语义是
不同。对于B oB(a)
,编译器尝试查找构造函数
可以使用给定的参数调用。在这种情况下,B::B(A*)
可以被调用,因为有Wrap<A>
的隐含转换
到A*
。对于B oB = a
,语义是隐式地将a
转换为
键入B
,然后使用B
的复制构造函数初始化oB
。 (该
实际的副本可以优化出来,但程序的合法性是
确定它好像不是。)并且没有隐含的转换
Wrap<A>
至B
,仅Wrap<A>
至A*
。
当然,赋值也适用,因为赋值运算符也是如此
采用A*
,因此隐式转换发挥作用。
答案 2 :(得分:5)
标准不允许链式隐式转换。如果允许,那么你可以编写这样的代码:
struct A
{
A(int i) //enable implicit conversion from int to A
};
struct B
{
B(const A & a); //enable implicit conversion from A to B
};
struct C
{
C(const B & b); //enable implicit conversion from B to C
};
C c = 10; //error
您不能指望10
会转换为A
,然后转换为B
,然后转换为C
。
B b = 10; //error for same reason!
A a = 10; //okay, no chained implicit conversion!
B ba = A(10); //okay, no chained implicit conversion!
C cb = B(A(10)); //okay, no chained implicit conversion!
C ca = A(10); //error, requires chained implicit conversion
同样的规则适用于隐式调用operator T()
的隐式转换。
考虑一下,
struct B {};
struct A
{
A(int i); //enable implicit conversion from int to A
operator B(); //enable implicit conversion from B to A
};
struct C
{
C(const B & b); //enable implicit conversion from B to C
};
C c = 10; //error
您不能指望10
会转换为A
,然后转换为B
(使用operator B()
),然后转换为C
。小号
不允许使用此类链式隐式转换。你要做到这一点:
C cb = B(A(10); //okay. no chained implicit conversion!
C ca = A(10); //error, requires chained implicit conversion
答案 3 :(得分:2)
这是因为C ++ Standard只允许一个用户定义的转换。根据§12.3/ 4:
最多一个用户定义的转换(构造函数或转换函数)隐式应用于单个转换 值。
B oB = a; // not tried: ob( a.operator T*() ), 1 conversion func+1 constructor
oB = a; // OK: oB.operator=( a.operator T*() ), 1 conversion func+1 operator=
作为一种解决方法,您可以使用显式形式来调用构造函数:
B oB( a ); // this requires only one implicit user-defined conversion