Cómo dar formato a mis propios objetos cuando se utiliza corrientes STL?
Pregunta
Deseo emitir mi propio objeto a una corriente STL, pero con un formato personalizado. Se me ocurrió algo como esto pero ya nunca he usado local e imbuir antes de que tenga ni idea de si esto tiene sentido y cómo implementar MyFacet y el operador <<.
Así que mis preguntas son: ¿Esto tiene sentido y cómo implementar MyFacet y el operador <<
?El siguiente es un ejemplo simplificado que muestra lo que quiero hacer.
struct MyObject
{
int i;
std::string s;
};
std::ostream &operator<<(std::ostream &os, const MyObject &obj)
{
if (????)
{
os << obj.i;
}
else
{
os << obj.s;
}
}
MyObject o;
o.i = 1;
o.s = "hello";
std::cout.imbue(locale("", new MyFacet(MyFacet::UseInt)));
std::cout << o << std::endl; // prints "1"
std::cout.imbue(locale("", new MyFacet(MyFacet::UseString)));
std::cout << o << std::endl; // prints "hello"
Solución
Bueno, una configuración regional se utiliza generalmente para permitir diferente formato de salida / entrada del mismo objeto basado en el formato local (la configuración regional especificada de hecho) que está presente. Para un buen artículo sobre esta Sede: http://www.cantrip.org/locale.html. Ahora tal vez es porque su ejemplo anterior se simplifica bastante, pero me parece que usted está tratando de llegar a una forma inteligente de cambiar entre la impresión de una parte de un objeto u otra. Si ese es el caso, podría ser más simple se limite a sobrecargar el operador de corriente para cada tipo y utilizar el interruptor si externamente.
De todos modos, no voy a fingir que soy un experto en facetas y locales, pero echar un vistazo a ese artículo, es bastante completo y le dará una mejor explicación de lo que lo hará!
Otros consejos
La implementación de su propio operador << para el trazo es generalmente una buena idea. Sin embargo nunca he necesitado para imbuir locales. No obstante lo probé y funcionó bien. Esto es lo que hice:
class my_facet : public std::locale::facet
{
public:
enum option{
use_string,
use_numeric
};
//Unique id for facet family, no locale can contain two
//facets with same id.
static std::locale::id id;
my_facet(option o=use_numeric):
facet(0),
_option(o)
{//Initialize reference count to zero so that the memory
//management will be handled by locale
};
option get_option() const {return _option;};
protected:
option _option;
};
std::locale::id my_facet::id(123456); //Facet family unique id
std::ostream& operator<<(std::ostream& os, const myobj& o)
{
std::locale const& l = os.getloc();
if( std::has_facet<my_facet>(l) ){
my_facet const& f = std::use_facet<my_facet>(l);
switch(f.get_option()){
case my_facet::use_numeric:
os << "Using numeric! ";
break;
case my_facet::use_string:
os << "Using string! ";
break;
default:
os << "Unhandled case.. ";
break;
}
return os;
}
os << "Default case when no facet has been set";
return os;
}
A continuación, para imbuir a un local con la faceta:
std::locale mylocale(locale("US"), new my_facet(my_facet::use_numeric));
std::cout.imbue(mylocale);
Sin embargo, una forma más elegante sería la implementación de las diferentes facetas de la misma familia faceta que puede ser reemplazado en el entorno local.