iam*_*ind 6 c++ constructor compiler-errors typecast-operator
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
}
Run Code Online (Sandbox Code Playgroud)
什么时候oB被构造然后为什么B::B(A*)不被调用Wrap<T>::operator T ()?[注意:在下一个声明中B::operator = (A*)调用Wrap<T>::operator T ()]
Mat*_* M. 10
问题在于,隐式调用的用户定义转换的数量受标准限制(为1).
B ob = a;
Run Code Online (Sandbox Code Playgroud)
意味着两次用户转换:
a:Wrap<A>::operator A*()应该被称为B::B(A*)应该被调用@James Kanze的解释:这种语法称为"复制初始化",实际上相当于B ob = B(a)(大多数时候复制都被删除).这与B ob(a)"直接初始化" 不同,并且可以起作用.
如果您明确限定任何一项,它将起作用,例如:
B ob = B(a);
Run Code Online (Sandbox Code Playgroud)
另一方面,对于第二种情况,没有问题:
ob = a;
Run Code Online (Sandbox Code Playgroud)
是短手:
ob.operator=(a);
Run Code Online (Sandbox Code Playgroud)
因此,只允许进行一次用户定义的转换.
编辑:
由于评论中需要(对基里尔的答案),我们可以猜测一下动机.
链式转换可能很长很长,因此:
此外,只要转换次数超过1次,您就会遇到必须检测到周期的风险(即使可能不需要诊断,并且要遵守实施质量).
所以,因为有必要限制以避免无限长的搜索(它可能没有指定,只需要最少),并且因为超过1我们可能有新的问题(周期),那么1似乎是一个很好的限制,毕竟.
这是因为你正在使用"复制初始化".如果您写下以下声明oB:
B oB(a);
Run Code Online (Sandbox Code Playgroud)
,它应该工作.两个初始化的语义是不同的.因为B oB(a),编译器试图找到一个可以使用给定参数调用的构造函数.在这种情况下,B::B(A*)
可以调用,因为有从implicite转换Wrap<A>
到A*.因为B oB = a,语义是隐式转换a为类型B,然后使用复制构造函数B进行初始化oB.(可以优化实际副本,但是程序的合法性被确定为不是.)并且没有隐式转换为
Wrap<A>to B,仅为Wrap<A>to A*.
当然,赋值是有效的,因为赋值运算符也需要a A*,因此隐式转换起作用.
标准不允许链式隐式转换.如果它被允许,那么你可以编写这样的代码:
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
Run Code Online (Sandbox Code Playgroud)
你不能指望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
Run Code Online (Sandbox Code Playgroud)
同样的规则适用于隐式调用的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
Run Code Online (Sandbox Code Playgroud)
您不能指望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
Run Code Online (Sandbox Code Playgroud)