要爲不同的幀製作不同的類型,只需將其作爲模板參數。然後我們需要定義我們想要的類型的任何接口。下面是一些例子,你可以寫:
#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;
};
如果你想你的問題想確切的語法,你可以用template <typename T, Frames frame>
取代template <typename T, typename Tag, Tag kTag>
並進行必要的修改,或者你可以使用這種類型的別名:
template <typename T, Frames frame>
using MyTagWrapper = TagWrapper<T, Frames, frame>;
因此,混合兩種標記類型會導致編譯錯誤,但混合標記類型和未標記類型會轉換爲標記類型。所有剩下的就是定義標籤類型之間的轉換功能,這是很容易做到:
MyTagWrapper<T, frame1> to_frame1(MyTagWrapper<T, frame2> const&);
然後將此:
auto pt4 = (tf_1_to_2 * pt1) + pt2;
變成這樣:
auto pt4 = to_frame1(pt1) + pt2;
這有點不清楚。在我看來,你正在尋找像單元庫這樣的東西,你可以有'1m + 1m = 2m',但是'1m + 1N'是一個編譯錯誤。除非你想限制它,使它必須是完全相同的「單位」,所以你不能做像'1米/ 1秒= 1米/秒' – Justin
單位是一個很好的思考方式,但我想把任何東西變成多種相互排斥的「單位」。所以'TagWrapper'具有'Person'的接口,但不會與例如TagWrapper 交互。 –
daemacles
您無法完全複製'Person'的接口。你必須手動寫出你想要支持的接口(所以算術運算符等)。除此之外,你可以做的是添加一個get()成員函數來獲取底層類型。稍後,我會回到這裏回答您的問題 – Justin