重载泛型类型的模板类时检查运算符=时的自赋值
Checking for self-assignment when overloading operator= for template class of generic type
通常,当重载和分配运算符时,应该检查自赋值。在一个简单的非模板化类中,它如下所示:
MyClass& MyClass::operator=(const MyClass& rhs) {
if (this != &rhs) {
// do the assignment
}
return *this;
}
但是,假设MyClass
是模板化的,并且我们希望泛化类可以具有的泛型类型的赋值运算符重载:
template<class T>
class MyClass
{
template<class U>
friend class MyClass;
T value;
template<class U>
MyClass<T>& operator=(const MyClass<U>& rhs)
//... other stuff
}
template<class T>
template<class U>
MyClass<T>& MyClass<T>::operator=(const MyClass<U>& rhs)
{
if (this != &rhs) { //this line gives an error
value = (T)rhs.value;
}
}
在上述情况下,if (this != &rhs)
行将给出编译器错误。在MS Visual Studio 2015中,它是错误C2446:
'==':没有从 'const MyClas
*' 到 'MyClass *const ' 的转换
因此,在使用可以在右侧获取泛型模板化类型MyClass
实例的赋值运算符时,如何实现对自赋值的检查?
我建议重载operator=
.
template<class T>
class MyClass
{
template<class U>
friend class MyClass;
T value;
template<class U>
MyClass& operator=(const MyClass<U>& rhs) { ... }
// Overload for MyClass<T>
MyClass& operator=(const MyClass& rhs) { ... }
};
并仅在第二次重载中检查自分配。
我想指出的是,如果MyClass
的专业化不简单,上述逻辑就会中断。例如,如果您使用:
template<> class MyClass<int>:public MyClass<long> { ... };
不会调用用于检查自我分配的代码。请参阅 http://ideone.com/AqCsa3。
我肯定希望看到
Came to MyClass<T>::operator=(const MyClass& rhs)
作为该程序的输出。
same_object
是一个接受两个引用的函数,如果它们都引用同一个对象,则返回true;不是同一个地址,而是同一个对象。
template<class T, class U, class=void>
struct same_object_t {
constexpr bool operator()(T const volatile&, U const volatile&)const{return false;}
};
template<class T>
struct same_object_t<T,T,void> {
bool operator()(T const volatile& lhs, T const volatile& rhs)const{
return std::addressof(lhs) == std::addressof(rhs);
}
};
template<class T, class U>
struct same_object_t<T,U,
typename std::enable_if<
std::is_base_of<T, U>::value && !std::is_same<T,U>::value
>::type
>:
same_object_t<T,T>
{};
template<class T, class U>
struct same_object_t<T,U,
typename std::enable_if<
std::is_base_of<U, T>::value && !std::is_same<T,U>::value
>::type
>:
same_object_t<U,U>
{};
template<class T, class U>
constexpr bool same_object(T const volatile& t, U const volatile& u) {
return same_object_t<T,U>{}(t, u);
}
template<class T>
template<class U>
MyClass<T>& MyClass<T>::operator=(const MyClass<U>& rhs)
{
if (!same_object(*this, rhs)) {
value = static_cast<T>(rhs.value);
}
return *this;
}
活生生的例子。
由于联合和标准布局"第一成员"地址共享,两个不同的对象可以共享一个地址,以及数组和数组的第一个元素。 这些案例从same_object
返回false
。
private
/protected
继承可以打破这一点,就像通过多个路径从类型 T 继承的 U 类型一样。
相关文章:
- 重载Singly Linked List中的赋值运算符
- 使用赋值运算符重载从类中返回jobject
- 标准库类型的赋值运算符的引用限定符
- 复制构造函数、赋值运算符C++
- 标准::变体的赋值运算符
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 基类和派生类的多态赋值运算符
- 为用户定义的类正确调用复制构造函数/赋值运算符
- CRTP 中的复制赋值运算符 - gcc vs clang 和 msvc
- 为什么初始化时没有调用重载赋值运算符?
- 赋值运算符重载和自赋值
- C++矢量复制构造函数和赋值运算符是否也复制保留空间?
- Qt PL/SQL - 赋值运算符 - 字符串缓冲区太小
- 使用 OR 运算符赋值
- 交换与使用std::map[]运算符赋值(const问题)
- 为什么派生类不使用基类运算符=(赋值运算符)?
- 如何解决VC++2012生成运算符=赋值和复制构造函数的错误
- 商运算符赋值
- 使用重载的下标运算符赋值
- 在移动运算符/赋值运算符中,我应该使用std::move还是std::forward