2013-04-23 29 views
7

Quali sono i modelli che devo specializzare per supportare std :: get?Abilita std :: supporto per la classe

struct MyClass { 
    int a; 
}; 

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

Cosa devo a specializzarsi per essere in grado di fare:

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

penso 'std :: get (...)' è veramente destinato ad essere applicato solo a 'std :: tuple' e che sarebbe meglio definire la propria funzione per la tua classe personalizzata. –

risposta

11

std::get non è un punto di personalizzazione per la libreria standard; i tre sovraccarichi del modello di funzione (per pair, tuple e array) non consentono esplicitamente sovraccarichi definiti dall'utente, pertanto 17.6.4.2.1p1 si applica e l'aggiunta di una dichiarazione di sovraccarico del proprio modello funzione è un comportamento non definito.

noti che get come qualificato nome è un punto di personalizzazione come C++ 17; è utilizzato dal protocollo structured binding declaration per accedere agli elementi tuple; ma questo è un nome non qualificato, non il nome qualificato std::get.

Detto questo, se si dovesse a scrivere:

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

e allo stesso modo per il riferimento rvalue e sovraccarichi di riferimento const, il programma sarebbe probabilmente funzionare come previsto.

Tuttavia, non ha senso visto che lo standard fornisce già array:

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

Grazie. _'std :: get' non è un punto di personalizzazione_ è quello che mi stavo chiedendo davvero. –

+1

Questo non cambia in C++ 17, in modo che gli utenti possano far funzionare le proprie classi con i binding strutturati, sfruttando la ricerca di _ "' get (e) ', dove get viene cercato dalla ricerca dipendente dall'argomento" _? Vedi [cppreference] (http://en.cppreference.com/w/cpp/language/structured_binding), caso 2 –

+1

@underscore_d non del tutto; questo è 'get' come un nome non qualificato, non il nome qualificato' std :: get'. È comunque un punto importante; Grazie! – ecatmur

0

Sto indovinando si desidera implementare alcuni algoritmi che devono accedere a arbitrari array come contenitori utilizzando indici in fase di compilazione e quindi mirare a utilizzare alcune funzioni (come std::get) per eseguire in modo uniforme tale attività ?! In questo caso, è lo stesso business di rendere begin e end disponibili per la classe. Basta dichiarare una funzione get nello spazio dei nomi in cui è stata dichiarata la propria classe contenitore e lasciare che ADL faccia il proprio lavoro.

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

Nel vostro algoritmo è sufficiente utilizzare get (senza il prefisso std namespace) e ADL chiamerà la funzione corretta. Quindi, per le strutture standard come array, tuple e pairstd::get viene invocato e per il contenitore la funzione get che hai fornito.

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 non funziona sull'istanza esplicita dei modelli di funzione; in fase di analisi, il nome 'get' non viene riconosciuto come modello, quindi le parentesi angolari vengono analizzate come operatori di confronto. (Prova a mettere 'MyContainer' in un namespace.) – ecatmur