2010-01-07 4 views
6

J'ai une classe similaire à boost :: any, en ce sens qu'il s'agit d'une classe de conteneur gabarit. Je voudrais avoir une méthode pour écrire la valeur contenue dans une chaîne. Toutefois, si le type contenu ne fournit pas d'opérateur d'insertion de flux, j'aimerais que ma méthode renvoie une requête par défaut plutôt que de ne pas compiler. Ci-dessous est aussi proche que je suis venu, et devrait préciser à ce que je suis en train de faire:Comment créer un opérateur d'insertion de flux "par défaut" en 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(); 
     } 
    }; 
} 

Cela fonctionne assez bien, avec quelques mises en garde. Par exemple, si je veux réellement fournir un opérateur d'insertion surchargé pour une classe, cet opérateur doit soit être dans le même espace de noms que la classe, soit être dans l'espace de noms W pour être considéré.

Il a également des problèmes avec tout type qui a déjà un opérateur std :: non-membre < <, par ex. char et std :: string. Si T est l'un de ces types, alors la ligne oss << t_ ci-dessus devient ambiguë. Cela peut être contourné en ajoutant pour ces types de surcharge à l'intérieur l'espace de noms W, par exemple:

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

Ma question est, quelqu'un trouve une meilleure méthode que cela? Pourquoi dois-je ajouter mes propres surcharges pour des choses comme std :: string? Est-ce que tout est pris en charge selon la norme, ou est-ce que je profite d'un comportement non standard? (Je teste avec g ++ 4.3.3)

Répondre

3

Voici un code dont je me souviens avoir vu il y a quelque temps dans une classe de construction de compilateur. Je pensais que c'était particulièrement intelligent (si ce n'est pas «propre») alors je me suis retenu.

De 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)"; 
    } 

Lorsque vous construisez votre objet conteneur, maintenez un pointeur vers la fonction d'impression de la variable:

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

Ensuite, utilisez plus tard la fonction imprimante() pour afficher le contenu valeur si possible.

Espérons que cela aide.

+0

Cela ne semble pas détecter mes propres opérateurs d'insertion de flux personnalisés. L'objet const & operator a la priorité, peut-être parce qu'il est déclaré comme faisant partie de la fonction? Si j'essaie d'extraire l'objet et son opérateur << de la fonction, il finit par ne plus pouvoir correspondre à quoi que ce soit ... – JimSteele1222

+0

En fait, rayez cela: il récupère les opérateurs d'insertion de flux tant qu'ils sont dans le même espace de noms que le classe T. Je n'arrive pas à trouver un moyen, par exemple, de fournir un opérateur d'insertion de flux pour le vecteur . – JimSteele1222

Questions connexes