6
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*)中调用 for ]Wrap<T>::operator T ()

4

4 回答 4

10

问题是隐式调用的用户定义转换的数量受标准限制(为 1)。

B ob = a;

意味着两个用户转换:

  • on 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 我们可能会遇到新问题(循环),所以 1 似乎与任何限制一样好.

于 2011-05-25T06:22:16.280 回答
7

这是因为您正在使用“复制初始化”。如果您编写以下声明oB

B oB(a);

,它应该工作。两种初始化的语义不同。对于B oB(a),编译器试图找到一个可以使用给定参数调用的构造函数。在这种情况下,B::B(A*) 可以调用,因为存在从Wrap<A> to的隐式转换A*。因为B oB = a,语义是隐式转换a为类型B,然后使用 的复制构造函数B进行初始化oB。(实际的副本可以优化出来,但程序的合法性被确定为好像不是。)并且没有隐式转换 Wrap<A>to B,只有Wrap<A>to A*

当然,赋值是有效的,因为赋值运算符也采用 a A*,因此隐式转换开始发挥作用。

于 2011-05-25T08:15:25.063 回答
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

您不能指望 that10将转换为Awhich then 将转换为Bwhich then 转换为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
于 2011-05-25T06:27:27.660 回答
2

这是因为 C++ 标准只允许一种用户定义的转换。根据§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
于 2011-05-25T06:17:19.393 回答