为什么没有为给定的转换操作符调用构造函数?

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)

意味着两次用户转换:

  • on 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似乎是一个很好的限制,毕竟.


Jam*_*nze 7

这是因为你正在使用"复制初始化".如果您写下以下声明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*,因此隐式转换起作用.


Naw*_*waz 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
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)