模板化赋值运算符问题
我想确保赋值运算符中的 *this != &rhs 。但它不会编译。有什么建议吗?
template <typename T>
class A {
public:
A() {
std::cout << "Default Constructor" << std::endl;
}
A(const T& t) : m_t(t) {
std::cout << "Templated Constructor" << std::endl;
}
template <typename X>
A( const A<X>& rhs ) : m_t( (static_cast< A<T> >(rhs)).m_t ) {
std::cout << "Copy Constructor" << std::endl;
}
template <typename X>
const A& operator=( A<X>& rhs) {
std::cout << "Assignment Operator" << std::endl;
if (this != static_cast< A<T>* > (&rhs) )
m_t = rhs.get();
return *this;
}
T get() { return m_t; }
private:
T m_t;
};
class base {};
class derived : public base {};
int main()
{
A<base*> test1;
A<derived*> test2;
test1 = test2;
}
I want to make sure that *this != &rhs in the assignment operator. But it won't compile. Any suggestions?
template <typename T>
class A {
public:
A() {
std::cout << "Default Constructor" << std::endl;
}
A(const T& t) : m_t(t) {
std::cout << "Templated Constructor" << std::endl;
}
template <typename X>
A( const A<X>& rhs ) : m_t( (static_cast< A<T> >(rhs)).m_t ) {
std::cout << "Copy Constructor" << std::endl;
}
template <typename X>
const A& operator=( A<X>& rhs) {
std::cout << "Assignment Operator" << std::endl;
if (this != static_cast< A<T>* > (&rhs) )
m_t = rhs.get();
return *this;
}
T get() { return m_t; }
private:
T m_t;
};
class base {};
class derived : public base {};
int main()
{
A<base*> test1;
A<derived*> test2;
test1 = test2;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果它确实让您烦恼,您总是可以拥有第二个不需要强制转换的非模板化
operator=
。为了避免冗余,如果 this != &rhs 它可以显式调用模板版本。说明如何调用正确的运算符的示例:If it really bothers you, you can always have a second non-templated
operator=
that doesn't need the cast. To avoid redudancy, if this != &rhs it can explicitly invoke the template version. Example illustrating how the right operator gets called:您在这里尝试执行的操作
是执行从
A<衍生*>
到A
的static_cast
。这是
static_cast
的作用:A
不是A
的基类,因此会出现错误。一般来说,显然
A
永远不会是A
的基类,即使X
可转换为T。所以这个演员阵容就不在考虑之列了。
解决方案是使用
reinterpret_cast(&rhs)
代替。更新
我在这方面做了更多工作;这是结果。我先给出代码,然后再评论。
设置代码
到目前为止发生的事情的要点:
iff
它们的“正常”版本,即“你应该做什么”的版本。Aggregate
分配给Aggregate
,第二个用于将Aggregate
分配给Aggregate<
T2>。这直接来自托尼的回答,这是“正确的方式”。operator==
可以为未隐式定义的类型伪造一个比较运算符。具体来说,当U
不是基本类型时,我们需要包含Aggregate
的代码进行编译。练习代码
这就是所有乐趣所在:
这将输出:
那么...我们从中学到什么?
我想说这意味着平等检查是多余的,应该被删除。
但是,如果:
T1
和T2
是相同类型或存在隐式转换,和T1
的赋值运算符或T2
的转换运算符非常昂贵(这会立即将原语从图片中删除),和bool 运算符== (const T1& lhs, const T2& rhs)
的运行时间成本比上述赋值/转换运算符小得多然后检查相等性可能有意义(取决于您期望
operator==
返回true
的频率)。结论
如果您打算仅将
Aggregator
与指针类型(或任何其他原语)一起使用,那么相等性测试是多余的。如果您打算将其与昂贵的构造类类型一起使用,那么您将需要一个有意义的相等运算符来配合它们。如果您也将其与不同类型一起使用,则还需要转换运算符。
What you are trying to do here
is perform a
static_cast
from aA<derived*>
to aA<base*>
.Here's what
static_cast
does:A<base*>
is not a base class ofA<derived*>
, hence the error.In general, obviously
A<T>
will never be a base class ofA<X>
, even ifX
is convertible toT
. So that cast is out of the equation.A solution would be to use
reinterpret_cast<void*>(&rhs)
instead.Update
I worked on this some more; here are the results. I 'll give the code first, then comment.
Setup code
The important points on what is going on so far:
iff
their "normal", do-what-you-should version would.Aggregate<T>
toAggregate<T>
and the second for assigningAggregate<T1>
toAggregate<T2>
. This is straight from Tony's answer, and it's "the right way".operator==
is there to fake a comparison operator for types where one is not implicitly defined. Specifically, we need that for code that containsAggregate<U>
to compile whenU
is not a primitive type.Excercise code
Here's where all the fun is:
This will output:
So... what do we learn from this?
I 'd say this means that the equality check is superfluous and should be removed.
However, if:
T1
andT2
are the same type or an implicit conversion exists, andT1
's assignment operator orT2
's conversion operator is expensive (this immediately takes primitives out of the picture), andbool operator== (const T1& lhs, const T2& rhs)
that has a much smaller runtime cost than the above assignment/conversion operatorsthen checking for equality might make sense (depends on how often you would expect
operator==
to returntrue
).Conclusion
If you intend to use
Aggregator<T>
just with pointer types (or any other primitive), then the equality tests are superfluous.If you intend to use it with expensive to construct class types, then you 'll need a meaningful equality operator to go with them. If you use it with different types as well, conversion operators will also be required.
在您的情况下无需测试自分配。与一些教程可能建议的相反,自赋值测试通常对于重载赋值运算符来说并不是必需的。
仅当(实现不佳的)赋值运算符首先释放资源,然后创建新资源作为右侧操作数资源的副本时,才需要这样做。只有这样,自分配才会变成灾难性的,因为左侧对象会同时释放右侧操作数(本身)的资源。
There is no need to test for self-assignment in your case. Self-assignment tests, contrary to what some tutorials may suggest, are not essential to overloaded assignment operators in general.
That is only needed if the (poorly implemented) assignment operator first releases the resources and then creates new resources to be the copy of the right-hand operarand's resources. Only then would self-assignment turn out to be catastrophic, because the left-hand object would have released the resources of the right-hand operand (itself) at the same time.
我个人认为以下是最优雅的解决方案。我不知道为什么我一开始没有得到这一点 - 我最初使用的是 Bloodshed C++ 编译器,它似乎失败了 - 但 g++ 这是最干净的?
如果人们不同意我的观点,我会删除我的答案并将其交给其他人。请注意,A* 实际上表示 A*,但需要注释
I personally think the following is the most elegant solution. I am not sure why I didn't get that in the first place - I initially was using the bloodshed c++ compiler and it seemed to fail - but g++ this is cleanest?
If people disagree with me, I'll remove my answer and give it to someone else. Note that the A* actually means A* but is note required
好的版本:实现与类本身类型完全相同的复制赋值运算符:
“脏”版本:将每个对象的地址转换为
intptr_t
并比较普通值:编辑:实际上,第二个版本不起作用,因为使用了编译器生成的复制赋值运算符。因此,您只需自己实施一个即可。 --结束编辑
另外,您不需要使用
rhs.get()
,只需使用rhs.m_t
,因为您可以从类本身访问私有成员。The good version: Implement the copy assignment operator that takes exactly the same type as the class itself:
The 'dirty' version: Cast the address of each object to a
intptr_t
and compare the plain values:Edit: Actually, this second version won't work, because of the compiler generated copy assignment operator that is used instead. So just implement one yourself. --end edit
Also, you don't need to use
rhs.get()
, just userhs.m_t
, as you can access private members from the class itself.