我正在尝试定义一个在“CoordinateSystem”参数上强类型的3d“坐标”类。我正在使用的当前机制的简化版本:
class CoordinateBase {
protected:
double a, b, c;
/* millions of constructors */
}
class System1 : protected CoordinateBase {
public:
double& X() {return a;}
double& Y() {return b;}
double& Z() {return c;}
protected:
/* millions of constructors */
}
class System2 : protected CoordinateBase {
public:
double& Lat() {return a;}
double& Lon() {return b;}
double& Alt() {return c;}
protected:
/* millions of constructors */
}
template<typename T>
class Coordinate : public T {
public:
/* millions of constructors */
}
这样可行,但我对树中每个级别涉及的样板量(无参数/显式值/复制/移动构造函数,赋值运算符)不满意。我想保留为不同系统的坐标轴设置不同名称的能力。
使用类似CRTP的东西似乎很有帮助;然后我可以让成员将实际坐标值存储在Coordinate类中,并使用静态多态从System1和System2获取它们。不幸的是,我不能这样做:
template<typename T>
class Coordinate : public T<Coordinate<T>>
或者,至少,编译器不会让,可能是因为我缺少一些语法。
我考虑的另一种可能性是将所有启用/禁用逻辑放在Coordinate中:
template<typename T>
class Coordinate {
public:
std::enable_if<std::is_same<T, System1>::value, double&> X() {return a;}
private:
double a;
}
但是这会变得相当丑陋并且把所有令人不快的模板机器放在这个类的无辜用户会看到它。
我不确定这类事情的最佳方法是什么。如何在保持我喜欢的界面的同时避免定义如此多的样板构造函数/赋值运算符?
答案 0 :(得分:3)
SQLiteOpenHelper
上面的代码不是有效的C ++,因为template<typename T>
class Coordinate : public T<Coordinate<T>>
是一种类型,但您正在使用它就好像它是T
一样。这也不是CRTP - 这是正确CRTP的一个例子:
template
您可以尝试以这种方式使用CTRP:
template <typename T>
struct base
{
auto& as_derived() { return static_cast<T&>(*this); }
const auto& as_derived() const { return static_cast<const T&>(*this); }
};
struct derived : base<derived>
{
// ...
};
答案 1 :(得分:0)
结束解决这个问题:
template<typename T>
class CoordinateBase {
protected:
Coordinate<T>* upcast() {return static_cast<Coordinate<T>*>(this);}
const Coordinate<T>* upcast() const {return static_cast<const Coordinate<T>*>(this);}
};
class System1 : private CoordinateBase<System1> {
double& X() {return upcast()->c1;}
// other coordinates etc.
};
template<typename T>
class Coordinate : public T {
public:
/* Constructors */
private:
double c1;
double c2;
double c3;
friend class System1;
};
typedef Coordinate<System1> System1Coordinate;
所以sorta-CRTP,但我依靠惯例来制作static_cast&lt;&gt;安全而不是模板参数和约定。我已经省略了一些名称空间和意味着CoordinateBase和System1不会对公众公开的事情。
这种方法的优点:
using
它们缺点: