c++通过不同的模板参数生成不同的类成员

问题描述 投票:0回答:1

对于 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;
  }
};

我不知道如何定义模板类。

c++ templates
1个回答
0
投票

虽然您所要求的可以通过模板专业化来实现,但处理两种不同的类型可能更容易。但无论如何我们还是要尝试一下。


为了简单起见,我在代码中使用

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

实例

© www.soinside.com 2019 - 2024. All rights reserved.