繁体   English   中英

偏好转换运算符而非转换构造函数

[英]prefer conversion operator over conversion constructor

我有以下代码片段:

class A
{
public:
  A() : x_(0), y_(0) {}

  A(int x, int y) : x_(x), y_(y) {}

  template<class T>
  A(const T &rhs) : x_(rhs.x_), y_(rhs.y_)
  {
  }

  int x_, y_;
};

class B
{
public:
  B() {}

  operator A() const { return A(c[0],c[1]); }
  int c[2];
};

void f()
{
  B b;
  (A)b; // << here the error appears, compiler tries to use 
        //         template<class T> A(const T &rhs)
}

为什么编译器使用A的构造函数? 如何让它使用B的转换运算符到A

我用的是MSVS2010编译器。 它给了我这些错误:

main.cpp(9): error C2039: 'x_' : is not a member of 'B'
          main.cpp(17) : see declaration of 'B'
          main.cpp(28) : see reference to function template instantiation 'A::A<B>(const T &)' being compiled
          with
          [
              T=B
          ]
main.cpp(9): error C2039: 'y_' : is not a member of 'B'
          main.cpp(17) : see declaration of 'B'

UPD :好吧,Nawaz所说的真正有效的隐式转换。 让它变得更复杂,如何使下面的代码工作?

void f()
{
  std::vector<B> b_vector(4);
  std::vector<A> a_vector( b_vector.begin(), b_vector.end() );
}

UPDA是第三方库中的类,我无法编辑代码,所以我无法删除A的转换构造函数。

UPD :我目前发现的最简单的解决方案是定义转换B构造函数的特化。 它可以在第三方lib之外完成:

template<> A::A( const B &rhs ) : x_(rhs.c[0]), y_(rhs.c[1]) {}

究其原因不仅是因为它认为(A)b是一样的A(b) 标准说明了关于显式类型转换(5.4):

由...执行的转换

  • 一个const_cast(5.2.11),

  • 一个static_cast(5.2.9),

  • static_cast后跟const_cast,

  • reinterpret_cast(5.2.10),或

  • 一个reinterpret_cast后跟一个const_cast,

可以使用显式类型转换的强制转换表示法执行。 适用相同的语义限制和行为。

基本上这意味着即使对于(A)b显式类型转换(即如果你使用((A)b);也要防止它是变量声明)。 它使用static_cast的规则。 现在让我们看一下标准关于static_cast (5.2.9)的内容:

对于某些发明的临时变量t(8.5),如果声明“T t(e);”格式正确,则可以使用static_cast(e)形式的static_cast将表达式e显式转换为类型T. 这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。 如果T是引用类型(8.3.2),则结果是左值,否则为右值。 当且仅当初始化将其用作左值时,表达式e用作左值。

如果你做static_cast<A>(b) ,它基本上看A(b)是否格式正确; 它是 仅仅因为模板函数copy-constructor的实际实例化失败,它不会使实际声明形成错误,因此它使用它并最终失败。

从5.4 / 1和5.4 / 5开始,C-cast从列表中选择“最佳选择”C ++。 在这种情况下,这是一个static_cast

然后从5.2.9 / 2:

对于某些发明的临时变量t(8.5),如果声明“T t(e);”形成良好,则可以使用static_cast(e)形式的static_cast将表达式e显式地转换为类型T. 这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。 如果T是引用类型(8.3.2),则结果是左值,否则为右值。 当且仅当初始化将其用作左值时,表达式e用作左值。

所以它在尝试任何其他选项之前选择构造函数。

在这种情况下,您已定义了两个转换以获得相同的最终结果,但该语言具有特定的规则,规定它将始终使用可用的构造函数。 您应该离开构造函数并将操作符更改为显式的as type函数。

编辑OP的编辑:我认为你不能使用vector iter, iter构造函数。 您需要从一个空向量开始,并使用带有push_back的for循环或使用std::transform

(A)b; // << here the error appears, compiler tries to use 

这是对A 明确投射。 因此,调用A的构造函数将b转换为A

A a(1,2);
a = b ; //this will invoke user-defined conversion of B (implicit conversion)

演示: http//www.ideone.com/K9IxT

如上所述,给定在格式良好的构造函数和转换运算符之间进行选择,编译器将始终调用构造函数。 但是,如果您愿意,可以直接调用转换运算符:

A a = b.operator A();

关于如何使其工作的问题的第二部分,我将使用std::transform而不是在第三方库命名空间中修改/添加某些东西,除非只有这个库有详细记录并且你应该这样做专门化这个构造函数:

a_vector.reserve( b_vector.size() );
std::transform( b_vector.begin(), b_vector.end(), 
  std::back_inserter( a_vector ), boost::bind( &B::operator A, _1 ) );

语法(A)bA(b)相同,这是一种结构。 如果你想要一个static_cast ,那么你必须明确地使用static_cast

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM