![](/img/trans.png)
[英]How to prefer `operator<<` over generic `operator T()` conversion?
[英]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() );
}
UPD : A
是第三方库中的类,我无法编辑代码,所以我无法删除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)b
与A(b)
相同,这是一种结构。 如果你想要一个static_cast
,那么你必须明确地使用static_cast
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.