2013-04-23 7 views
7

Jakie szablony muszę wyspecjalizować, aby obsługiwać std :: get?Włącz obsługę std :: get w klasie

struct MyClass { 
    int a; 
}; 

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

Co muszę specjalizują się, aby móc zrobić:

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

myślę 'std :: dostać (...)' jest naprawdę mają być stosowane tylko do 'std :: tuple' i że byłoby lepiej, aby zdefiniować własną funkcję dla twojej niestandardowej klasy. –

Odpowiedz

11

std::get nie jest punktem przystosowanie dla standardowej biblioteki; przeciążenia szablonu trzyfunkcyjnego (dla pair, tuple i array) nie dopuszczają jawnie przeciążenia zdefiniowanego przez użytkownika, więc obowiązuje 17.6.4.2.1p1, a dodanie deklaracji własnego szablonu funkcji przeciążenia jest niezdefiniowanym zachowaniem.

Należy zauważyć, że get jako niewykwalifikowany nazwa jest punkt dostosowanie jak C++ 17; jest używany przez protokół structured binding declaration w celu uzyskania dostępu do elementów podobnych do tupetów; ale jest to nazwa niekwalifikowana, a nie kwalifikowana nazwa std::get.

Powiedział, że jeśli były napisać:

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

i podobnie na odniesienie rvalue i przeciążeń const odniesienia, program będzie prawdopodobnie działać zgodnie z oczekiwaniami.

Jednak nie ma sensu skoro średnia dostarcza już array:

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

Dzięki. _'std :: get' nie jest parametrem dostosowującym_ jest tym, o czym naprawdę się zastanawiałem. –

+1

Nie zmienia tej wersji w C++ 17, dzięki czemu użytkownicy mogą tworzyć własne klasy z powiązaniami strukturalnymi, wykorzystując wyszukiwanie _ "get (e)", gdzie wynik jest sprawdzany przez wyszukiwanie zależne od argumentów " _? Zobacz [cppreference] (http://en.cppreference.com/w/cpp/language/structured_binding), Przypadek 2 –

+1

@underscore_d niezupełnie; to 'get' jako niekwalifikowana nazwa, a nie kwalifikowana nazwa' std :: get'. To jednak ważna kwestia; dzięki! – ecatmur

0

Zgaduję chcesz wprowadzić pewne algorytmy, które potrzebują dostępu do dowolnych tablica podobnych pojemników za pomocą indeksów w czasie kompilacji i w związku z tym zamierzają użyć jakiejś funkcji (np. std::get), aby równomiernie wykonać to zadanie ?! W takim przypadku jest to ta sama działalność, co udostępnienie begin i end dla Twojej klasy. Po prostu zadeklaruj funkcję get w przestrzeni nazw, w której zadeklarowałeś swoją klasę kontenera, i pozwól ADL wykonać swoje zadania.

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

W swoim algorytmie po prostu użyć get (bez prefiksu std przestrzeni nazw) i ADL wezwie prawidłową funkcję. Tak więc standardowe konstrukcje, takie jak array, tuple i std::get są wywoływane, a dla Twojego kontenera podana jest funkcja get.

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 nie działa w jawnym tworzeniu szablonów funkcji; w czasie analizy nazwa 'get' nie jest rozpoznawana jako szablon, dlatego nawiasy kątowe są analizowane jako operatory porównania. (Spróbuj umieścić 'MójContainer' w przestrzeni nazw.) – ecatmur