2016-05-09 1 views
1

Je suis en train d'écrire une bibliothèque et il faut stringifier les objets.Problèmes avec la résolution de surcharge et l'opérateur << pour les types de modèles

J'ai choisi de prendre en charge operator<<(ostream&....

Une autre chose est que ma bibliothèque doit fournir la stringification par défaut des types qui n'ont pas operator<<(ostream&... dans le formulaire {?}.

Le problème est avec des types comme vector<> basés sur des modèles - Je ne veux pas l'utilisateur d'écrire 2 pour vector<int> et surcharges vector<float> - mais je ne peux pas le faire fonctionner.

Voici le code:

#include <string> 
#include <type_traits> 
#include <sstream> 
#include <vector> 
#include <iostream> 
using namespace std; 

namespace has_insertion_operator_impl { 
    typedef char no; 
    typedef char yes[2]; 

    struct any_t { 
     template <typename T> 
     any_t(T const&); 
    }; 

    no operator<<(ostream const&, any_t const&); 

    yes& test(ostream&); 
    no test(no); 

    template <typename T> 
    struct has_insertion_operator { 
     static ostream& s; 
     static T const&  t; 
     static bool const value = sizeof(test(s << t)) == sizeof(yes); 
    }; 
} 

template <typename T> 
struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator<T> {}; 

template <class T> 
typename enable_if<has_insertion_operator<T>::value, string>::type stringify(const T& in) { 
    stringstream stream; 
    stream << in; 
    return stream.str(); 
} 

template <class T> // note the negation here compared to the one above 
typename enable_if< ! has_insertion_operator<T>::value, string>::type stringify(const T&) { 
    return "{?}"; 
} 

// USER CODE: 

struct myType {}; 

ostream& operator<<(ostream& s, const myType&) { s << "myType"; return s; } 

template<typename T> 
ostream& operator<<(ostream& s, const vector<T>&) { s << "vector<T>"; return s; } 

int main() { 
    myType a;   cout << stringify(a) << endl; // prints "myType" 
         cout << stringify(6) << endl; // prints "6" 
    vector<int> v(5); cout << stringify(v) << endl; // prints "{?}" instead of "vector<T>" 

    return 0; 
} 

myType et l'entier à la fois obtenir, mais pour le de chaîne de caractères vector<int> je reçois la valeur par défaut {?}.

J'ai besoin d'aide à ce sujet - c'est un showstopper pour moi. J'ai besoin des surcharges operator<<(ostream&... fournies par l'utilisateur pour travailler sans modification - et tout cela en C++ 98.

+1

_ "mes en-têtes ne doivent pas faire glisser n'importe quoi avec eux - pas même ou même " _ Twofold: 1. [Déclarations directes] (http://stackoverflow.com/questions/625799/resolve-header-include-circular -dependencies-in-c) 2. [Implémentations de modèles] (http://stackoverflow.com/questions/495021/why-can-templates-only- be-implemented-in-the-header-file). Peut-être que c'est juste une restriction idiote, pourriez-vous clarifier sur le raisonnement pourquoi s'il vous plaît? –

+0

Veuillez fournir un [mcve]. Accent sur le minimum. Il n'y a aucun moyen que vous ayez besoin de 140 lignes de code réparties sur trois fichiers pour reproduire le problème que vous voyez. – Barry

+1

Préférez également absolument '' pour transférer manuellement la déclaration de tous les types 'std'. C'est le but de l'existence de cette en-tête. – Barry

Répondre

0

Turns sur tout ce que je devais faire était supprimer l'espace de noms avec la mise en œuvre de l'opérateur insertion trait de sorte que le repli operator<<(ostream&... finit dans la portée mondiale - expliqué here.

1

Pour correspondre au vecteur dont vous avez besoin pour fournir de meilleurs candidats pour vos stringize fonctions

Pour 11 C++ ce serait:

template <template <typename...> class V, typename... Args> 
typename enable_if< !has_insertion_operator<V<Args...>>::value, string>::type stringify(const V<Args...>&) { 
    return "template {?}"; 
} 
// also add enable_if for yes with code identical to the one in template<typename T> 

Puisque vous avez besoin C++ 98, je crains vous devrez fournir un certain nombre de surcharges de template pour 1 à N (disons 5 ou 10) args. Comme ça.

template <template <typename> class V, typename T0> 
... 
template <template <typename, typename> class V, typename T0, typename T1> 
... 
/// etc 

Par exemple vector dans votre cas a 2 arguments de modèle, et correspondra à la seconde paire de yes/no fonctions