2012-05-30 6 views
10

Tengo una función en mi espacio de nombres ns que me ayuda a imprimir contenedores STL. Por ejemplo:boost :: formato e impresión personalizada a std containers

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; 
} 

Esto funciona muy bien para la impresión con operator << directamente:

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

Sin embargo, utilizando boost::format es imposible:

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

El problema es bastante obvia: Boost no tiene ni idea que me gustaría usar mi operator << personalizado para imprimir tipos que no tienen nada que ver con mi espacio de nombres. Además de agregar una declaración using en boost/format/feed_args.hpp, ¿hay alguna manera conveniente de hacer que boost::format busque mi operator <<?

+1

que suger fuertemente Si echa un vistazo a [esta pregunta] (http://stackoverflow.com/q/4850473/500104), ya que básicamente responde a sus necesidades. Sin embargo, no votaré para cerrar como un duplicado, ya que su pregunta real es diferente (sobre el 'operador <<'). – Xeo

+2

@Xeo: Mi código real utiliza un enfoque muy similar para imprimir cualquier contenedor. De todos modos, el problema no es cómo imprimir un contenedor con 'operator <<', sino cómo hacer que la misma sobrecarga funcione para cosas donde Koenig no hace lo que yo quiero. –

Respuesta

4

Creo que la manera más limpia es proporcionar un envoltorio delgado en su propio espacio de nombres para cada uno de los operadores que desea anular. Para su caso, puede ser:

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

Entonces utilizar de esta manera:

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

Esto es muy similar a la solución que realmente utilicé. También publiqué mi solución. –

1

Usted puede intentar algo como esto:

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

El problema es como se ha señalado, debido a ADL (dependiente de búsqueda argumento - a menudo se atribuye a Andrew Koenig, pero yo creo que no debe recibir toda la culpa) .

Incluso en su contexto local, no funcionaría en una función de plantilla en la que pretenda usar su operator<<.

Un truco engañoso es poner el operator<< que defina en namespace std. Eso está prohibido, pero podría funcionar en su caso, pero solo si se pone antes de su uso y ese podría ser el problema.

Puede haber otras opciones, como la definición de su propia plantilla de Conjunto. Experimenté con

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

pero no pude conseguir una solución que funcionó sin la yuyoyuppe

using np::operator<<; 

proporcionado.

5

La solución realidad fui con es bastante similar a Contestaro de, pero funciona para nada:

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

} 

Así que uso es:

boost::format("%1%") % Formatable(x); 
Cuestiones relacionadas