对于 exmaple,不要为 2D 点创建 z 成员,而为 3D 点创建 z 成员,例如:
template <typename T, int DIM>
class Point {
private:
T x;
T y;
#if(DIM==3) { //3 dimension add z;
T z;
}
public:
Point(T x, T y) : x(x), y(y) {}
#if(DIM==3) {
Point(T x, T y, T z) : x(x), y(y), z(z) {}
}
template <typename U, int D>
friend std::ostream& operator<<(std::ostream& os, const Point<U, D>& p) {
#if(D==3) {
os << p.x << " " << p.y << " " << p.z;
}
#else {
os << p.x << " " << p.y;
}
return os;
}
};
我不知道如何定义模板类。
虽然您所要求的可以通过模板专业化来实现,但处理两种不同的类型可能更容易。但无论如何我们还是要尝试一下。
为了简单起见,我在代码中使用
struct
而不是 class
,因为它们的成员默认标记为 public
。如果这不是您想要的行为,只需将它们更改为 class
es 和/或将您想要的任何内容标记为 public
/protected
/private
。
我使用名称
PointImpl
来表示那些不同的部分,主要是成员,然后从中派生出实际的 Point
。 Point
将包含两个 struct
之间的通用方法。
首先,我们将使用模板参数声明我们的类型。
template <typename T, std::size_t N>
struct PointImpl;
在此之后,我们需要实际定义两个
struct
,其大小为 2
和 3
。一种天真的解决方案可能是
template <typename T>
struct PointImpl<T, 3> {
T x;
T y;
T z;
};
与
2
相同,但没有最后一个成员。然而,这会使编写可以采用不同大小的 PointImpl
的函数(例如 std::ostream& operator<<
重载)变得更加困难。您可以对它们使用模板专门化,但有一种更简单的方法。我们只是要添加一个下标运算符。
const T& operator[](std::size_t idx) const {
switch (idx) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
throw std::out_of_range("Point<T, 3>::operator[] access out of bounds!");
}
}
这允许我们仅使用索引而不是成员的实际名称来访问所有成员(再次对大小
2
实现相同的操作,而无需 case 2
并更改错误消息)。
我们现在有了最终
Point
的基本构建块,并且可以从 PointImpl
中导出它。
template <typename T, std::size_t N>
struct Point : PointImpl<T, N> {
};
您现在可以在此
Point
的主体中添加您想要/需要的任何方法。一个重要的部分是operator[]
。
T& operator[](std::size_t idx) {
return const_cast<T&>(std::as_const(*this)[idx]);
}
在此片段中,我们首先将
const
应用于 *this
,然后从那里调用它的 operator[]
。由于我们已经在 const T& operator[] const
中实现了 PointImpl
,所以效果非常好。然后我们再次删除之前应用的 const
,这样我们就可以只返回 T&
。
现在,这将遮蔽 const
中的 PointImpl
版本,为了解决此问题,我们在 Point
的主体中添加以下行:
using PointImpl<T, N>::operator[];
从这里开始,剩下的事情就变得非常简单了。您可以向
Point
添加不同的方法,如下所示:
std::size_t size() const {
return N;
}
void zero(T defaultValue = {}) {
for (std::size_t i{ 0 }; i < N; ++i) {
(*this)[i] = defaultValue;
}
}
friend std::ostream& operator<<(std::ostream& os, const Point& point) {
for (std::size_t i{ 0 }; i < N - 1; ++i) {
os << point[i] << ' ';
}
os << point[N - 1];
return os;
}
请注意,使用
Point
与 2
或 3
以外的尺寸将导致编译错误,因为没有为这些定义 PointImpl
。