X类包含2个数据。模板化赋值运算符接受任何类型并将其分配给成员' d。但是,我仍然希望复制分配正常工作。在MSVC 2010中,行' b = a;'调用模板赋值运算符而不是复制赋值。如何重载分配以正确区分或在内部区分模板分配?
class X
{
public:
X() : x(0), d(0.0) {}
X(X const & that) { x = that.x; d = that.d; }
X& operator=(X const & that) { x = that.x; d = that.d; }
template<typename T>
X& operator=(T && y) {
//if (T is X&)
// operator=(static_cast<X const &>(that));
//else
// d = y;
return *this;
}
int x;
double d;
};
void f()
{
X a;
X b;
a = 5;
a = 3.2;
b = static_cast<X const &>(a); // calls copy assignment
b = a; // calls template assignment
}
答案 0 :(得分:3)
在MSVC 2010中,行&#39; b = a;&#39;调用模板赋值运算符而不是复制赋值
应该调用赋值运算符模板。我们有两个可行的重载:
X& operator=(X const &);
X& operator=(X& ); // [T = X&]
订购转换序列的方法之一是[over.ics.rank]:
标准转换序列S1是比标准转换序列更好的转换序列 S2如果[...] S1和S2是引用绑定(8.5.3),引用引用的类型相同 除了顶级 cv - 限定符之外的类型,并且S2引用的引用引用的类型比由S1初始化的引用的类型更多 cv - 限定指。
复制赋值运算符引用的类型比赋值运算符模板更符合 cv ,因此首选赋值运算符模板。你添加static_cast
强制编译器选择复制赋值运算符的原因是现在两个函数都采用完全相同的参数(X const&
),我们只是更喜欢函数不是函数模板专业化。
避免这种情况的简单方法是SFINAE输出操作员模板,使其不适用于X
或源自X
的内容:
template <typename T,
typename = std::enable_if_t<
!std::is_base_of<X, std::decay_t<T>>::value
>>
X& operator=(T&& );
这将使赋值运算符模板不再是b=a;
的可行候选者,因此复制赋值运算符变得非常适合。
答案 1 :(得分:-1)
可能是2个函数而不是模板赋值:
X& operator=(double that) { d = that; return *this; }
X& operator=(int that) { d = that; return *this; }
在C ++ 11中还有std::is_same
,请参阅:How to check for the type of a template parameter?