2015-09-15 4 views
6

Ein häufiges Designproblem, in das ich hineingeraten bin, ist, dass ich zwei Variablen zusammenbündele und dann die Fähigkeit verliere, sie sinnvoll zu referenzieren.Kann ich std :: pair verwenden, aber erste und zweite Mitgliedsnamen umbenennen?

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? 

hielt ich habe das Schreiben grundlegende Strukturen statt, aber dann habe ich viel über die Vorteile verlieren, die mit std::pair kommen:

  • make_pair
  • Nichtmitglied überladene Operatoren
  • Swap
  • bekommen
  • usw.

Gibt es eine Möglichkeit zum Umbenennen oder Bereitstellen einer alternativen Kennung für die Datenelemente first und second?

Ich hatte gehofft, dass all die Funktionen zu nutzen, die std::pair akzeptieren,
aber noch in der Lage sein, sie auf folgende Weise zu verwenden:

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

Ich glaube nicht, Sie können. Vielleicht eine Klasse erstellen, die std :: pair umschließt? –

+1

Wahrscheinlich Overkill für die Aufgabe wie definiert, aber [BOOST_FUSION_DEFINE_STRUCT] (http://www.boost.org/doc/libs/1_59_0/libs/fusion/doc/html/fusion/adapted/define_struct.html) können Sie generieren Eine Struktur, die Vergleichsoperatoren, Swap usw. automatisch generiert, aber mit benutzerdefinierten Feldnamen/-typen. – Mankarse

+1

Wie wäre es mit 'structs: std :: pair {int & x = this-> first; int & y = das-> zweite; }; '? – Slava

Antwort

7

Eine Möglichkeit, dies umgehen könnte, ist zu verwenden, std::tie. Sie können tie() die Rückkehr in Variablen, die Sie benannt haben, damit Sie gute Namen haben.

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 

Ein weiterer Vorteil dabei ist, wenn Sie jemals die Funktion ändern, um ein Tupel zurück tie() wird auch mit daran arbeiten.

+0

Hurb Sutter Segel es wäre schön, in der Lage zu sein, die Variablen in tie zu deklarieren, aber ich kann jetzt keinen Vorschlag finden. Ich habe Folgendes gefunden: https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/4yWRnzX7J7Y – NathanOliver

6

Sie können nur freie Funktionen machen:

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 Nieblers tagged könnte hier helfen. Die Grundidee ist, dass Sie Getter wie folgt zu erstellen:

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

Und Sie können y_tag ähnlich implementieren (nur die Namen Memberfunktion y() ändern). Dann:

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

Dann

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

können Sie verwenden

#define _px first 
#define _py second 
Verwandte Themen