2011-09-16 10 views
6

Staram się zrobić to w ten sposób:jak operator przeciążenia << dla tablicy w C++?

template <typename T> 
ostream &operator<<(ostream &os, T &arr) 
{ /*...*/ } 

Ale może T reprezentowania tablicę? Czy prawidłowe jest przeciążenie operatora << dla macierzy?


EDIT:

Zgodnie z radą Kerrek SB, tu jest moja realizacja dla <<:

template <typename T, unsigned int N> 
ostream &operator<<(ostream &os, const T (&arr)[N]) 
{ 
    int i; 
    for(i = 0; i < N; i++) 
     os << arr[i] << " "; 
    os << endl; 
    return os; 
} 

Czy moja realizacja prawda? Dostałem błąd kompilacji.

Odpowiedz

7

Można to zrobić:

template <typename T, unsigned int N> 
std::ostream & operator<<(std::ostream & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

To działa tylko na tablicach w czasie kompilacji, oczywiście. Zauważ, że nie masz uprawnień do utworzenia tego szablonu, gdy T jest wbudowanym typem lub typem w przestrzeni nazw std!

Prawdopodobnie najlepiej zrobić to w linii, jeśli to możliwe, ponieważ spowodujesz oddzielne tworzenie instancji dla każdego N. (The pretty printer ma tego przykładem.)

Można zauważyć jednak, że szablon koc wprowadza dwuznaczność, gdyż os << "Hello" ma teraz dwa możliwe przeciążenia: szablon pasujący const char (&)[6] oraz (non-template) przeciążeniem wskaźnik od zaniku do wskaźnika const char *, które mają identyczne sekwencje konwersji. Możemy rozwiązać ten problem poprzez wyłączenie naszą przeciążenie dla tablic Znak:

#include <ostream> 
#include <type_traits> 

template <typename T, unsigned int N> 
typename std::enable_if<!std::is_same<T, char>::value, std::ostream &>::type 
operator<<(std::ostream & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

W rzeczywistości, aby być jeszcze bardziej ogólnie można również dokonać basic_ostream Parametry Parametry szablonu:

template <typename T, unsigned int N, typename CTy, typename CTr> 
typename std::enable_if<!std::is_same<T, char>::value, 
         std::basic_ostream<CTy, CTr> &>::type 
operator<<(std::basic_ostream<CTy, CTr> & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

Ze względu na fakt, że T musi być typem zdefiniowanym przez użytkownika, można nawet zastąpić is_same<T, char> przez is_fundamental<T>, aby uzyskać nieco więcej sprawdzeń (ale użytkownicy nadal nie mogą tego używać w przypadku tablic standardowych typów bibliotek).

+0

Dzięki, ale ja don zrozumieć, dlaczego powoduje on osobne tworzenie instancji dla każdego N, jeśli nie jest zaimplementowane w linii? – Alcott

+0

Cóż, jest to szablon, więc każda instancja szablonu może skończyć jako osobna funkcja w twoim pliku binarnym. Jeśli wbudujesz, możliwe jest całkowite uniknięcie wywołania funkcji, chociaż ostatecznie zależy to od kompilatora. –

+0

rozumiem.Z tym operatorem << posiadającym 2 argumenty szablonu, jak mogę określić drugi argument N? Najwyraźniej nie mogę po prostu użyć "cout << ar;", czy mogę? – Alcott

3

Innym sposobem można zrobić to byłoby coś jak poniżej:

template<typename T> 
ostream& operator<<(ostream &out, const std::pair<T, int>& array) 
{ 
    //...code 
    return out; 
} 

Gdzie T odbędzie wskaźnik do tablicy (czyli będzie to wskaźnik typu, że tablica będzie rozkładać się) , a część pary będzie miała rozmiar macierzy. Następnie można go używać jak poniżej:

int array[10]; 
//...some code that initializes array, etc. 

cout << make_pair(array, 10); 

jeden plus z tej metody jest to również pracować dla dynamicznych tablic (czyli tablice przeznaczyć na stercie, etc.)

+0

Spróbuję. Dzięki – Alcott

+0

Mam bardzo słabe przeczucie, że możesz mieć kłopoty z ADL tutaj, jeśli twoje 'T' nie jest typem zdefiniowanym przez użytkownika, chociaż nie jestem tego pewien. –

+0

Testowałem go z wbudowanym typem, takim jak 'int' ... wydawało się działać dobrze ... Nie mogę się domyślić, dlaczego byłoby to sprzeczne z regułami ADL. Jeśli masz obiekt 'std :: pair ', szablon powinien umożliwiać wyprowadzenie typu 'T' i odrzucenie dowolnych wystąpień za pomocą' std :: pair 'gdzie' U' nie jest typu 'int' . – Jason

Powiązane problemy