2010-01-07 9 views
6

Mam klasę podobną do boost :: any, ponieważ jest to klasa kontenerów z szablonem. Chciałbym mieć metodę zapisu zawartej wartości na łańcuchu. Jeśli jednak zawartego typu nie zapewnia operator wstawiania strumienia, chciałbym, aby moja metoda zwróciła niektóre domyślne tring zamiast kompilacji. Poniżej jest tak blisko jak ja przyszedł i powinien jasno, co próbuję zrobić:Jak utworzyć "domyślny" operator wstawiania strumienia w C++?

namespace W { 
    namespace hide { 
     template <typename T> 
     std::ostream& operator<<(std::ostream& out, const T& t) { 
      return std::operator<<(out, typeid(T).name()); 
     } 
    } 

    template <typename T> struct C { 

     T t_; 

     std::string ToString() const { 
      using namespace hide; 
      std::ostringstream oss; 
      oss << t_; 
      return oss.str(); 
     } 
    }; 
} 

To działa całkiem dobrze, z pewnymi zastrzeżeniami. Na przykład, jeśli chcę rzeczywiście dostarczyć przeciążonego operatora wstawiania dla klasy, wówczas ten operator musi albo być w tej samej przestrzeni nazw, co klasa, albo musi znajdować się w przestrzeni nazw W, aby mógł zostać uwzględniony.

Ma również problemy z każdym typem, który już ma std :: operator <, bez operatora, np. < <, np. char i std :: string. Jeśli T jest jednym z tych typów, linia oss << t_ powyżej staje się niejednoznaczna. Można to obejść dodając przeciążeń dla tych typów wewnątrz przestrzeni nazw W, na przykład:

std::ostream& operator << (std::ostream& out, const std::string& s) { 
    return std::operator <<(out, s); 
} 

Moje pytanie brzmi, czy ktoś znalazł lepszą metodą niż to? Dlaczego muszę dodawać własne przeciążenia dla rzeczy takich jak std :: string? Czy to wszystko jest obsługiwane zgodnie ze standardem, czy też korzystam z niestandardowego zachowania? (Testuję z g ++ 4.3.3)

Odpowiedz

3

Poniżej znajduje się kod, który pamiętam jakiś czas temu w klasie kompilatora. Myślałem, że to było szczególnie sprytne (jeśli nie "czyste"), więc trzymałem się tego.

Od http://www.cs.colorado.edu/~main/a++/tree.h

// If data of type T can be printed with the usual << operator, then 
    // print<T>(out, p) will interpret *p as a T object and print its 
    // value to out. Otherwise, a message is printed to out, indicating 
    // that objects of type T are not printable. 
    template<typename T> void print(std::ostream& out, const void* p) 
    { 
    // The first part of this code sets an enum value, is_printable, to 
    // be 1 if the data type T can be printed with the usual << 
    // operator. Otherwise, is_printable is set to zero. The programming 
    // technique is based on a note from Herb Sutter at 
    // http://www.gotw.ca/gotw/071.htm 
    class object 
    { 
    public: 
     object(T convert) { }; 
    }; 
    char operator << (std::ostream&, const object&); 
    enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 }; 

     // Notice that the boolean expression in the if-statement is known at 
    // compile time, so that only one of the two output statements will be 
    // compiled into object code. 
    if (is_printable) 
     out << *static_cast<const T*>(p); 
    else 
     out << "(value of type " << typeid(T).name() << " cannot be printed)"; 
    } 

Gdy tworzysz swój obiekt kontenera, przytrzymaj wskaźnik do funkcji drukowania dla zmiennej:

void (*printer)(std::ostream&, const void*); 
printer = print<T>; 

Później korzystać z funkcji drukarki(), aby wyświetlić zawarte wartość, jeśli to możliwe.

Mam nadzieję, że to pomoże.

+0

Wygląda na to, że nie widzę żadnego z moich własnych niestandardowych operatorów wstawiania strumienia. Obiekt i operator const ma pierwszeństwo, może dlatego, że jest zadeklarowany jako część funkcji? Jeśli spróbuję wyciągnąć obiekt i jego operatora << z funkcji, to kończy się to, że nie mogę niczego dopasować ... – JimSteele1222

+0

Właściwie to zróbmy: pobieramy operatory wstawiania strumienia, o ile są one w tej samej przestrzeni nazw co klasa T. Nie mogę znaleźć sposobu, aby na przykład zapewnić operator wstawiania strumienia dla wektora . – JimSteele1222