C++ 如何包装对象,使其成为无法交互的单独类型?
我正在处理大量坐标数据,想想预定义的库类型C++ 如何包装对象,使其成为无法交互的单独类型?,c++,linear-algebra,physics,template-meta-programming,C++,Linear Algebra,Physics,Template Meta Programming,我正在处理大量坐标数据,想想预定义的库类型 struct Point3d { double x,y,z; }; 以及来自Eigen和OpenCV的类似内容 现在,每个点的坐标表示在某个参考系中。我希望类型系统跟踪表示每个点的帧。类似于 enum Frames { frame1, frame2 }; using Point_1 = TagWrapper<Point3d, frame1>; using Point_2 = TagWrapper<Point3d, frame2&g
struct Point3d { double x,y,z; };
以及来自Eigen和OpenCV的类似内容
现在,每个点的坐标表示在某个参考系中。我希望类型系统跟踪表示每个点的帧。类似于
enum Frames { frame1, frame2 };
using Point_1 = TagWrapper<Point3d, frame1>;
using Point_2 = TagWrapper<Point3d, frame2>;
Point3d untagged_pt = ...;
Point_1 pt1 = ...;
Point_2 pt2 = ...;
Transform<frame1, frame2> tf_1_to_2 = ...; // from frame1 to frame2
// Compile time error, pt1 and pt2 are in different frames
auto pt3 = pt1 + pt2;
// Ok!, and typeof(pt4) == Point_2
auto pt4 = (tf_1_to_2 * pt1) + pt2;
// Compile time error, pt2 is not in frame1
auto pt5 = tf_1_to_2 * pt2;
// Ok!, and typeof(pt5) == Point_1
auto pt5 = untagged_pt + pt1;
枚举帧{frame1,frame2};
使用点_1=标记包装器;
使用点_2=标记包装器;
点3D未标记_pt=。。。;
点1 pt1=。。。;
点2 pt2=。。。;
将tf_1_转换为_2=…;/从第1帧到第2帧
//编译时错误,pt1和pt2在不同的帧中
自动pt3=pt1+pt2;
//好的!,和类型(pt4)=点2
自动pt4=(tf_1_至_2*pt1)+pt2;
//编译时错误,pt2不在frame1中
自动pt5=tf_1_至_2*pt2;
//好的!,和类型(pt5)=点1
自动pt5=未标记的_pt+pt1;
最好我可以用任何“标记”包装任何类型,使其成为标记类型。然后,所有相似标记的类型在相互使用时表现为其未标记的类型,但是将对象与不同的标记混合在一起会导致编译时错误。我认为,在未标记类型和标记类型之间进行操作的结果变为标记也是有意义的
这类似于单位,但我想把任何东西都转换成多种相互排斥的“单位”。例如,
TagWrapper
具有Person
的接口,但不会与TagWrapper
交互。要为不同的帧创建单独的类型,只需将其作为模板参数。然后我们需要在类型上定义我们想要的任何接口。下面是一个你可以写的例子:
#include <utility> // for std::move
#include <iterator> // for std::begin, std::end
template <typename T, typename Tag, Tag kTag>
class TagWrapper
{
T value_;
public:
TagWrapper(T value)
: value_{ std::move(value) }
{}
// Note: This will allow you to add a T to a TagWrapper<T, ...>
// However, if T had an implicit constructor, you wouldn't be able
// to use that. If you wanted to support it, you'd have to 3x the operator overloads
// you implement. That is, you'd also need:
//
// friend auto operator+(T const& lhs, TagWrapper<T, Tag, kTag> const& rhs);
// friend auto operator+(TagWrapper<T, Tag, kTag> const& lhs, T const& rhs);
friend auto operator+(TagWrapper<T, Tag, kTag> const& lhs, TagWrapper<T, Tag, kTag> const& rhs)
{
return TagWrapper<T, Tag, kTag>{ lhs.value_ + rhs.value_ };
}
friend auto operator*(TagWrapper<T, Tag, kTag> const& lhs, TagWrapper<T, Tag, kTag> const& rhs)
{
return TagWrapper<T>{ lhs.value_ + rhs.value_ };
}
// the other arithmetic operators...
// You'd also want to do comparison operators
// Because it's impossible to completely delegate member functions on to
// everything that T can do, provide accessors to T. You may also prefer
// to define conversions, explicit or implicit:
//
// operator T const&() const { return value_; }
// explicit operator T const&() const { return value_; }
T const& get() const { return value_; }
T& get() { return value_; }
// As an example of generally wrapping, you could do this:
auto begin() { return std::begin(value_); }
auto begin() const { return std::begin(value_); }
auto end() { return std::end(value_); }
auto end() const { return std::end(value_); }
// This would make it so that if your type T was a "collection", then
// TagWrapper<T, ...> is as well. You could even use TagWrapper<T, ...>
// in a for-each loop
// Provide some way to see what the tag is. You may or may not want to expose this
static Tag tag = kTag;
};
变成这样:
auto pt4 = to_frame1(pt1) + pt2;
这有点不清楚。在我看来,您正在寻找类似于单元库的东西,在这里您可以拥有
1m+1m=2m
,但1m+1N
是一个编译错误。除非你想限制它,使它必须是完全相同的“单位”,所以你不能做类似于1m/1s=1m/s
Units是一个很好的思考方式,但我想把任何东西都变成多种相互排斥的“单位”。例如,TagWrapper
具有Person
的接口,但不会与TagWrapper
交互。您不能完全复制Person
的接口。您必须手动写出您想要支持的接口(例如算术运算符等)。除此之外,您还可以添加一个get()
成员函数来获取底层类型。过一会儿,我会回到这里回答你的问题//因为不可能完全将成员函数委托给//T可以做的一切,为T提供访问器。哦,好吧。。。这里正在等待reflecpr
和operator$
和ilk。
MyTagWrapper<T, frame1> to_frame1(MyTagWrapper<T, frame2> const&);
auto pt4 = (tf_1_to_2 * pt1) + pt2;
auto pt4 = to_frame1(pt1) + pt2;