鉴于以下类别:
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()
和Line2
时,最好的方法是什么,返回Vector2&
而不是Vector&
?我可以在m_min
内将m_max
和Vector2
提升为Line2
吗?或者以其他方式覆盖它们并且仍然具有Line
基类功能吗?
答案 0 :(得分: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();
};
答案 1 :(得分: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 Vector - 这是自动发生的。
答案 2 :(得分: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); }