Can I use std :: pair, but rename the names .first and .second?

The general design problem that I am facing is that I combine the two variables together and then lose the ability to refer to them in a meaningful way.

std::pair<int,int> cords; cord.first = 0; //is .first the x or y coordinate? cord.second = 0; //is .second the x or y coordinate? 

I thought about writing basic structures instead, but then I lose the many advantages that come with std::pair :

  • make_pair
  • non-member overloaded operators
  • swap
  • receive
  • and etc.

Is there a way to rename or provide an alternate identifier for the data members first and second ?

I was hoping to use all the functions that accept std::pair ,
but can still use them as follows:

 std::pair<int,int> cords; //special magic to get an alternative name of access for each data member. //.first and .second each have an alternative name. cords.x = 1; assert(cords.x == cords.first); 
+6
source share
4 answers

One way around this is to use std::tie . You can tie() return the variables you named so that you have good names.

 int x_pos, y_pos; std::tie(x_pos, y_pos) = function_that_returns_pair_of_cords(); // now we can use x_pos and y_pos instead of pair_name.first and pair_name.second 

Another advantage is that if you ever change a function to return a tuple, tie() will also work with this.

+7
source

You can simply perform free functions:

 int& get_x(std::pair<int, int>& p) { return p.first; } int& get_y(std::pair<int, int>& p) { return p.second; } int const& get_x(std::pair<int, int> const& p) { return p.first; } int const& get_y(std::pair<int, int> const& p) { return p.second; } 
+6
source

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; // extra polish for swap and converting from other tagged's. }; namespace std { template<typename Base, typename...Tags> struct tuple_size<tagged<Base, Tags...>> : tuple_size<Base> {}; template<size_t N, typename Base, typename...Tags> struct tuple_element<N, tagged<Base, Tags...>> : tuple_element<N, Base> {}; } 

Then

 using coord_t = tagged<std::pair<int, int>, x_tag, y_tag>; 
+2
source

you can use

 #define _px first #define _py second 
0
source

All Articles