Eric Nibler tagged can help here. The basic idea is that you create getters as follows:
struct x_tag { template<class Derived, class Type, std::size_t N> struct getter { Type& x() & { return std::get<N>(static_cast<Derived&>(*this)); } Type&& x() && { return std::get<N>(static_cast<Derived&&>(*this)); } const Type& x() const & { return std::get<N>(static_cast<const Derived&>(*this)); } const Type&& x() const && { return std::get<N>(static_cast<const Derived&&>(*this)); } }; };
And you can implement y_tag same way (just change the names of the member functions to y() ). Then:
template<class, class, class...> struct collect; template<class Derived, std::size_t... Ns, class... Tags> struct collect<Derived, std::index_sequence<Ns...>, Tags...> : Tags::template getter<Derived, std::tuple_element_t<Ns, Derived>, Ns>...{}; template<class Base, class... Tags> struct tagged : Base, collect<tagged<Base, Tags...>, std::index_sequence_for<Tags...>, Tags...> { using Base::Base;
Then
using coord_t = tagged<std::pair<int, int>, x_tag, y_tag>;
source share