0

给定以下类:

template <typename DataType, size_t Dimensions>
class Vector : public std::array<DataType, Dimensions> {
//stuff
};

template <typename DataType>
class Vector2 : public Vector<DataType, 2> {
//2d specific stuff
};

template <typename DataType, size_t Dimensions>
class Line {
public:
  Vector<DataType, Dimensions>& min();
  Vector<DataType, Dimensions>& max();

private:
  Vector<DataType, Dimensions> m_min;
  Vector<DataType, Dimensions> m_max;
};

template <typename DataType>
class Line2 : public Line<DataType, 2> {
//2d specific stuff
};

最好的方法是什么min()max()当调用 a 时Line2,返回 aVector2&而不是 a Vector&?我可以提升m_minm_maxVector2内部Line2吗?或者以其他方式覆盖它们并且仍然具有Line正确的基类功能?

4

3 回答 3

1

通常的方法是将模板分解为通用部分和特殊部分:

template <typename T, size_t N> struct LineCommon { /* ... */ };

template <typename T, size_t N> struct Line : LineCommon<T, N>
{
    Vector<T, N> & min();
    Vector<T, N> & max();
};

template <typename T> struct Line2 : LineCommon<T, 2>
{
    Vector2<T> & min();
    Vector2<T> & max();
};
于 2013-09-09T20:09:31.113 回答
1

我认为 Kerrek 建议将部分模板特化与公共基类一起使用是明智的,但您应该将该技术应用于 Vector 类型:

template <typename DataType, size_t Dimensions>
class VectorBase : public std::array<DataType, Dimensions> {
  // things common to all vectors here
};

template <typename DataType, size_t Dimensions>
class Vector : public VectorBase<DataType, Dimensions> {
   // nothing here
};

template <typename DataType>
class Vector<DataType, 2> : public VectorBase<DataType, Dimension> {
  // 2d specific stuff here, so for example:
  DataType& x() { return at(0); }
  DataType& y() { return at(1); }
};

template <typename DataType, size_t Dimensions>
class Line {
public:
  Vector<DataType, Dimensions>& min();
  Vector<DataType, Dimensions>& max();

private:
  Vector<DataType, Dimensions> m_min;
  Vector<DataType, Dimensions> m_max;
};

现在你可以这样做:

Line<double, 2> myLine;
double foo = myLine.max().x();

可以将该技术应用于 Line 类,但这仅对添加特定于 2D 线的函数有用,例如计算 Voronoi 图。您不需要任何 Line 特化来让 Line 返回一个 2D 矢量——这会自动发生。

于 2013-09-09T21:00:36.670 回答
0

有点更新,这就是我最终要做的事情:

因为某些本来属于 Base 类的函数需要返回 Vector 的副本,所以我需要使用CRTP。但我真的不喜欢所需的骨架代码。它过于复杂。

template <typename derived>
struct test_base {
  derived baz() { return *static_cast<derived *>(this); }
};

template <int N>
  struct test : public test_base<test<N>> {
};

template <>
struct test<2> : public test_base<test<2>> {
  test bar() { return *this; }
};

int main() {
  test<1> a = {};
  test<2> b = {};

  auto c = a.baz();
  auto d = b.baz();
  auto e = b.bar();

  return 0;
}

因此,为了寻求更扁平的层次结构,我使用了一些模板技巧:

#include <type_traits>

template <int N>
struct test {
  void foo() {}

  template <int P=N>
  typename std::enable_if<P == 2 && P == N>::type bar() {}

  template <int P=N>
  typename std::enable_if<P == 3 && P == N>::type baz() {}
};

int main() {
  test<1> a = {};
  test<2> b = {};
  test<3> c = {};

  a.foo();
  b.foo();
  c.foo();

  b.bar();
  c.baz();

  return 0;
}

在我看来,这似乎是一个更清洁的解决方案。它还允许我编写如下函数:

template <int P=N>
typename std::enable_if<P >= 2 && P == N>::type x() { return Base::operator[](0); }
于 2013-09-10T21:57:37.203 回答