2012-05-30 8 views
10

Ho una funzione nel mio spazio dei nomi ns che mi aiuta a stampare i contenitori STL. Per esempio:boost :: formato e stampa personalizzata di contenitori std

template <typename T> 
std::ostream& operator<<(std::ostream& stream, const std::set<T>& set) 
{ 
    stream << "{"; 
    bool first = true; 
    for (const T& item : set) 
    { 
     if (!first) 
      stream << ", "; 
     else 
      first = false; 
     stream << item; 
    } 
    stream << "}"; 
    return stream; 
} 

Questa grande opera per la stampa con operator << direttamente:

std::set<std::string> x = { "1", "2", "3", "4" }; 
std::cout << x << std::endl; 

Tuttavia, utilizzando boost::format è impossibile:

std::set<std::string> x = { "1", "2", "3", "4" }; 
boost::format("%1%") % x; 

Il problema è abbastanza ovvio: Boost ha idea che mi piacerebbe che usasse la mia custom operator << per stampare tipi che non hanno nulla a che fare con il mio spazio dei nomi. Oltre all'aggiunta di una dichiarazione using in boost/format/feed_args.hpp, c'è un modo conveniente per cercare per il mio operator <<?

+1

sono fermamente sugge d un'occhiata a [questa domanda] (http://stackoverflow.com/q/4850473/500104), poiché fondamentalmente risponde alle tue esigenze. Non voterò per chiudere come duplicato, tuttavia, poiché la tua domanda reale è diversa (riguardo all'operatore '' '). – Xeo

+2

@Xeo: il mio codice attuale utilizza un approccio molto simile alla stampa di qualsiasi contenitore. Ad ogni modo, il problema non è come stampare un container con 'operator <<', è come fare lo stesso sovraccarico per cose in cui Koenig non fa quello che voglio. –

risposta

4

Penso che il modo più semplice sia quello di fornire un involucro sottile nel proprio spazio dei nomi per ciascuno degli operatori che si desidera sovrascrivere. Per il vostro caso, può essere:

namespace ns 
{ 
    namespace wrappers 
    { 
     template<class T> 
     struct out 
     { 
      const std::set<T> &set; 

      out(const std::set<T> &set) : set(set) {} 

      friend std::ostream& operator<<(std::ostream& stream, const out &o) 
      { 
       stream << "{"; 
       bool first = true; 
       for (const T& item : o.set) 
       { 
        if (!first) 
         stream << ", "; 
        else 
         first = false; 
        stream << item; 
       } 
       stream << "}"; 
       return stream; 
      } 
     }; 
    } 

    template<class T> 
    wrappers::out<T> out(const std::set<T> &set) 
    { 
     return wrappers::out<T>(set); 
    } 
} 

Quindi utilizzare in questo modo:

std::cout << boost::format("%1%") % ns::out(x); 
+0

Questo è molto simile alla soluzione che ho effettivamente utilizzato. Ho pubblicato anche la mia soluzione. –

1

Si può provare qualcosa di simile:

namespace boost // or __gnu_cxx 
{ 
    using np::operator<<; 
} 
#include <boost/format/feed_args.hpp> 
0

Il problema, come già notato è a causa della ADL (lookup dipendenti argomento - spesso attribuito a Andrew Koenig, ma credo che non dovrebbe ottenere tutta la colpa) .

Anche nel contesto locale non funzionerebbe in una funzione modello in cui si intende utilizzare il operator<<.

Uno stratagemma consiste nel mettere lo operator<< definito in namespace std. Questo è verboten, ma potrebbe funzionare nel tuo caso, ma solo se viene messo prima del suo utilizzo e questo potrebbe essere il problema.

Potrebbero esserci ulteriori opzioni, come la definizione del proprio modello di Set. Ho sperimentato con

template<typename T> using Set=std::set<T>; 

ma non sono riuscito a ottenere una soluzione che ha funzionato senza il yuyoyuppe

using np::operator<<; 

fornito.

5

La soluzione Io sono andato con è molto simile a Answeror di, ma funziona per qualsiasi cosa:

namespace ns 
{ 

template <typename T> 
class FormatWrapper 
{ 
public: 
    explicit FormatWrapper(const T& x) : 
      ref(x) 
    { } 

    friend std::ostream& operator<<(std::ostream& stream, 
            const FormatWrapper<T>& self 
            ) 
    { 
     // The key is that operator<< is name lookup occurs inside of `ns`: 
     return stream << self.ref; 
    } 
private: 
    const T& ref; 
}; 

template <typename T> 
FormatWrapper<T> Formatable(const T& x) 
{ 
    return FormatWrapper<T>(x); 
} 

} 

Così utilizzo è:

boost::format("%1%") % Formatable(x); 
Problemi correlati