我有以下非类型模板:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
}
};
Point segment[MAX_SIZE];
};
如果我现在宣布两个不同的路径,我不能将不同段的元素相互分配,因为结构可能具有相同的结构,但是具有不同的类型:
Path<10> path_a ;
Path<30> path_b ;
path_a.segment[0].x = 1;
path_a.segment[0].y = 2;
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio)
当然,如果我将Point和Path的定义分开,那么赋值将起作用:
struct Point{
float x;
float y;
};
template<size_t MAX_SIZE>
struct Path{
Point segment[MAX_SIZE];
};
但这不是我想要的(这只是一个MWE),所以我想知道如何重载复制赋值运算符以使其工作。我尝试了很多变种,例如:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
{
x = that.x;
y = that.y;
return *this;
}
};
Point segment[MAX_SIZE];
};
但我总是得到同样的错误。所以我的问题是:是否有可能以一种允许在不改变结构布局的情况下分配以下形式的方式重载=?
path_b.segment[0] = path_a.segment[0];
答案 0 :(得分:5)
是的,可以进行此类设置。在核心,您需要一个接受所有类型的赋值运算符模板:
template<class T>
Point & operator = (const T & that)
作为基本解决方案,这就足够了。现在,它将适用于所有类型为x
和y
的兼容类型的类型,并为不适合的类型生成(通常)丑陋的错误消息。
如果这对您来说足够好,我们就完成了。
如果您有赋值运算符的其他重载,您可能希望有选择地禁用模板。为此,您需要检测Point
类并使用SFINAE:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
struct EnableAssignment {};
};
Point segment[MAX_SIZE];
};
然后使用这样的仪器:
template<class T, class U = typename T::EnableAssignment>
Point & operator = (const T & that)
上面的代码在函数模板中使用默认模板参数,该模板仅在C ++ 11中引入。在此之前,您必须以其他方式调用SFINAE:
template <class L, class R>
struct SfinaeThenRight
{
typedef R type;
};
template <class T>
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that)
答案 1 :(得分:2)
template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
无法工作,因为外部结构上的模板参数OTHER_SIZE
无法推断。你可以:
template<typename T>
Point & operator = (const T & that)
{
x = that.x;
y = that.y;
return *this;
}
请注意,如果没有传递成员x
和y
的内容,您将收到编译错误,这对于这种情况应该足够了。