2013-04-23 5 views
7

Was sind die Vorlagen, die ich spezialisieren muss, um std :: get zu unterstützen?Aktiviere std :: bekomme Unterstützung auf Klasse

struct MyClass { 
    int a; 
}; 

template <const size_t I> 
struct MyContainer { 
    MyClass array[I]; 
}; 

Was muss ich tun, um in der Lage sind spezialisiert:

MyContainer<16> mc; 
std::get<0>(mc); 
+0

Ich denke 'std :: get (...)' wirklich nur angewendet werden soll 'std :: tuple' und dass es besser wäre, eine eigene Funktion zu definieren, für Ihre benutzerdefinierte Klasse. –

Antwort

11

std::get keine Anpassung Punkt für die Standardbibliothek ist; Die drei Überladungen der Funktionsschablonen (für pair, tuple und array) erlauben nicht explizit benutzerdefinierte Überladungen, daher gilt 17.6.4.2.1p1 und das Hinzufügen einer Deklaration der eigenen Überlastung der Funktionsvorlage ist undefiniertes Verhalten.

anzumerken, dass get als unqualifizierte name ist eine Anpassung Punkt als die C++ 17; es wird vom Protokoll structured binding declaration verwendet, um auf tupelartige Elemente zuzugreifen; aber das ist als ein unqualifizierter Name, nicht der qualifizierte Name std::get.

Das heißt, wenn Sie zu schreiben waren:

namespace std { 
    template<size_t I, size_t N> MyClass &get(MyContainer<N> &c) { return c.array[I]; } 
} 

und in ähnlicher Weise für die rvalue Referenz- und konstante Referenz Überlastungen, Ihr Programm würde wahrscheinlich arbeiten, wie Sie es erwarten.

Allerdings gibt es zu sehen wenig Sinn wie der Standard bereits liefert array:

template<size_t N> using MyContainer = std::array<MyClass, N>; 
+0

Danke. _ 'std :: get' ist kein Anpassungspunkt_ ist, was ich wirklich gefragt habe. –

+1

Ändert dies nicht in C++ 17, so dass Benutzer ihre eigenen Klassen mit strukturierten Bindungen arbeiten lassen können, indem sie das Nachschlagen von _ "' get (e) 'verwenden, wobei get durch argumentabhängiges Nachschlagen nachgeschlagen wird" _? Siehe [cppreference] (http://en.cppreference.com/w/cpp/language/structured_binding), Fall 2 –

+1

@underscore_d nicht ganz; das ist '' '' als ein unqualifizierter Name, nicht der qualifizierte Name 'std :: get'. Es ist jedoch ein wichtiger Punkt; Vielen Dank! – ecatmur

0

Ich vermute, Sie einige Algorithmen implementieren mögen, die Compiler-Indizes mit Zugriff auf beliebige Array-artigen Behälter müssen und dafür, eine Funktion (wie std::get) zu verwenden, um diese Aufgabe gleichmäßig durchzuführen ?! In diesem Fall ist es das gleiche Geschäft wie begin und end für Ihre Klasse verfügbar. Sie deklarieren einfach eine Funktion get in dem Namespace, in dem Sie Ihre Containerklasse deklarierten, und lassen Sie ADL seine Aufgaben ausführen.

template <unsigned I, unsigned N> 
    MyClass& get (MyContainer<N>& c) { return c.array[I]; } 

    template <unsigned I, unsigned N> 
    MyClass const& get (MyContainer<N> const& c) { return c.array[I]; } 

In Ihrem Algorithmus nur Sie verwenden get (ohne std Namespacepräfix) und ADL wird die richtige Funktion aufrufen. Also, für die Standard-Strukturen wie array, tuple und pairstd::get wird aufgerufen und für Ihren Container die get Funktion, die Sie zur Verfügung gestellt.

int main(){ 
     std::array<int, 3> a {{0,1,2}}; 
     auto t = std::make_tuple(0.0, 1.0f, 2); 
     auto p = std::make_pair('0', 4.4); 
     MyContainer<3> c; 

     std::cout << get<1>(a) << std::endl; 
     std::cout << get<1>(t) << std::endl; 
     std::cout << get<1>(p) << std::endl; 
     std::cout << get<1>(c).a << std::endl; 

     return 0; 
    } 

Example

+3

ADL funktioniert nicht bei expliziter Instanziierung von Funktionsvorlagen; Bei der Parserzeit wird der Name "get" nicht als Vorlage erkannt, daher werden die spitzen Klammern als Vergleichsoperatoren analysiert. (Versuchen Sie, 'MyContainer' in einem Namespace zu platzieren.) – ecatmur

Verwandte Themen