2015-09-15 40 views
6

Powszechnie występującym problemem projektowym, który napotykam, jest to, że łączę ze sobą dwie zmienne, a następnie tracę możliwość odwoływania się do nich w znaczący sposób.Czy mogę użyć std :: pair, ale zmienić nazwy członków .first i .second?

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? 

ja już za pisanie podstawowe konstrukcjom zamiast, ale potem stracić dużo korzyści, które wraz z std::pair:

  • make_pair
  • non-member przeciążone operatorów
  • swapowe
  • uzyskać
  • itp.

Czy istnieje sposób zmiany nazwy lub zapewnienia alternatywnego identyfikatora dla elementów danych first i second?

Miałem nadzieję na wykorzystanie wszystkich funkcji, które akceptują std::pair,
ale nadal będą mogli z nich korzystać w sposób następujący:

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); 
+0

Nie sądzę, jest to możliwe. Może stworzyć klasę, która owija std :: pair ? –

+1

Prawdopodobnie przesada dla zadania zdefiniowanego, ale [BOOST_FUSION_DEFINE_STRUCT] (http://www.boost.org/doc/libs/1_59_0/libs/fusion/doc/html/fusion/adaptowane/define_struct.html) umożliwia generowanie struktura, która automatycznie generuje operatory porównania, wymiany itp., ale z niestandardowymi nazwami/typami pól. – Mankarse

+1

Co powiesz na 'struct cords: std :: pair {int & x = this-> first; int & y = this-> second; }; '? – Slava

Odpowiedz

7

Jeden sposób można obejść tego problemu jest użycie std::tie. Możesz tie() powrócić do zmiennych, które nazwałeś, abyś miał dobre nazwy.

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 

Inną korzyścią z tym jest, jeśli kiedykolwiek zmienić funkcję powrotu krotki tie() będą również pracować z tym.

+0

Hurb Sutter żagiel byłoby miło móc zadeklarować zmienne w tie, ale nie mogę znaleźć propozycji już teraz. Znalazłem: https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/4yWRnzX7J7Y – NathanOliver

6

Można po prostu zrobić darmowe funkcje:

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; } 
2

Eric Niebler na tagged może pomóc tutaj. Podstawowym założeniem jest to, że tworzenie pobierające tak:

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)); 
     } 
    }; 
}; 

I można w podobny sposób zaimplementować y_tag (wystarczy zmienić nazwy funkcji member aby y()). Następnie:

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> 
    {}; 
} 

następnie

using coord_t = tagged<std::pair<int, int>, x_tag, y_tag>; 
0

Można użyć

#define _px first 
#define _py second