Say I have a class representing automata, whose states are numbered (using state_t = unsigned
) and whose transitons are also numbered (using transition_t = unsigned
). Of course at some point I end up messing some calls because transition_t
and state_t
are the same type, so the compiler does not enforce the (semantic) type safety. That's easy to workaround by using a small class templated by a tag (struct transition_tag {}; struct state_tag {};
), so now transition_t
and state_t
are incompatible, good!
/// 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;
};
Further, I have two structures which are very much alike:
predecessors_t
maps from a transition to its predecessor transition (in the shortest path). For efficiency, it's astd::vector<transition_t>
.path_t
is a list of transition indexes. For efficiency it's astd::vector<transition_t>
.
And then again I have this issue that I use std::vector<transition_t>
for two completely different purposes. Of course, I could again introduce a wrapper templated by a tag, but then things become messy again. Public inheritance is very tempting (Thou shalt not inherit from std::vector)!
But really, I'm tired of ad-hoc solutions each time I want to introduce new types that are exactly like the base type, but just incompatible. Are there any recommendations on this regard? The public inheritance is really attractive, but wouldn't it introduce code bloat with tons on extra instantiations? Maybe the public composition (struct predecessors_t { std::vector<transition_t> v; };
) as recommended by Crashworks (https://stackoverflow.com/a/4353276/1353549) is a better option that scales better?
Is there anything in sight in the future of C++ to address this new?