【发布时间】:2017-01-17 16:13:31
【问题描述】:
假设我有一个表示自动机的类,它的状态被编号(using state_t = unsigned),其过渡也被编号(using transition_t = unsigned)。当然,在某些时候我最终会弄乱一些调用,因为transition_t 和state_t 是相同的类型,所以编译器不会强制执行(语义)类型安全。这很容易通过使用以标签 (struct transition_tag {}; struct state_tag {};) 为模板的小类来解决,所以现在 transition_t 和 state_t 不兼容,很好!
/// Lightweight state/transition handle (or index).
template <typename Tag>
struct index_t_impl
{
using index_t = unsigned;
constexpr index_t_impl(index_t i)
: s{i}
{}
// Disallow index1_t i{index2_t{42}};
template <typename T>
index_t_impl(index_t_impl<T> t) = delete;
bool operator==(index_t_impl t) const
{
return s == t.s;
}
// Disallow index1_t{42} == index2_t{42};
template <typename T>
bool operator==(index_t_impl<T> t) const = delete;
/// Default ctor to please containers.
index_t_impl() = default;
constexpr operator index_t() const { return s; }
/// Be compliant with Boost integer ranges.
index_t_impl& operator++() { ++s; return *this; }
/// Be compliant with Boost integer ranges.
index_t_impl& operator--() { --s; return *this; }
private:
index_t s;
};
此外,我有两个非常相似的结构:
-
predecessors_t从一个过渡映射到它的前一个过渡(在最短路径中)。为了提高效率,它是std::vector<transition_t>。 -
path_t是转换索引的列表。为提高效率,请使用std::vector<transition_t>。
然后我又遇到了这个问题,我将std::vector<transition_t> 用于两个完全不同的目的。当然,我可以再次引入一个以标签为模板的包装器,但随后事情又变得一团糟。公共继承很诱人(Thou shalt not inherit from std::vector)!
但实际上,每次我想引入与基本类型完全相同但不兼容的新类型时,我都厌倦了临时解决方案。在这方面有什么建议吗?公共继承确实很有吸引力,但它不会在额外的实例化上引入大量代码膨胀吗?也许 Crashworks (https://stackoverflow.com/a/4353276/1353549) 推荐的公共组合 (struct predecessors_t { std::vector<transition_t> v; };) 是一个更好的扩展选择?
C++ 的未来有什么可以解决这个新问题的吗?
【问题讨论】:
-
我不知道它是否会成为标准,但你可以看看这里:stackoverflow.com/questions/28916627/strong-typedefs
标签: c++ types stl c++14 type-safety