Pregunta

my_macro << 1 << "hello world" << blah->getValue() << std::endl;

debe expandirse en:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
¿Fue útil?

Solución

#define my_macro my_stream()
class my_stream: public std::ostringstream  {
public:
    my_stream() {}
    ~my_stream() {
        ThreadSafeLogging(this->str());
    }
};
int main() {
    my_macro << 1 << "hello world" << std::endl;
}

Se crea un temporal del tipo my_stream, que es una subclase de ostringstream. Todas las operaciones a que el trabajo temporal como lo harían en un ostringstream.

Cuando los extremos de los estados (es decir. La derecha después del punto y coma en toda la operación de impresión en main ()), el objeto temporal sale del ámbito y se destruye. Las llamadas my_stream destructor ThreadSafeLogging con los datos "recogidos" previamente.

Probado (g ++).

Gracias / créditos a dingo por señalar cómo simplificar todo el asunto, así que no necesito el operator<< sobrecargado. Lástima upvotes no se pueden compartir.

Otros consejos

¿No podrías derivar de ostream y proporcionar su propia implementación segura hilo? Posteriormente, se podría simplemente hacer

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

y obtener exactamente la misma funcionalidad sin macros y usando C ++ correctamente?

No. El problema es que sin el uso de sintaxis de la función, un macro se limita a solamente siendo reemplazado donde está.

Pero si estaban dispuestos a usar la sintaxis de la función, a continuación, puede sustituir nada, tanto antes como después de los argumentos.

my_macro(1 << "hello world" << blah->getValue() << std::endl);

Usted podría definiendo MiMacro como:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());

Tome un vistazo a google-GLOG , lo hacen utilizando un objeto temporal instanciado con un

LOG(INFO) << "log whatever" << 1;

y también tienen otras macros interesantes como LOG_IF et al.

Teniendo en cuenta que tiene estas líneas incluidas en algún lugar de su código, sí es posible

#include <iostream>
#include <sstream> 

macro __LINE__ se define por todos los compiladores standart. Por lo que podemos utilizarlo para generar un nombre de variable cual es diferente cada vez que use la macro:)

Esta es una nueva versión que se ve, ya que sólo una instrucción de un comunicado: (Edited)

#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
     Var(s, __LINE__).x<2; ++Var(s, __LINE__).x)  \
    if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
    else Var(s, __LINE__).oss

// So you can use it like this 
int main() 
{ 
    if (4 != 2)
        my_macro << 4 << " hello "  << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 

Developper probablemente no necesitará utilizar esta macro dos veces en la misma línea porque de simplicidad de << operador. Pero en caso de que necesite esto, se puede cambiar el uso de __LINE__ por __COUNTER__ (que no es estándar!). Gracias a este consejo para Quuxplusone

Aquí hay otro truco desagradable vi en otro lugar. Tiene una desventaja significativa en comparación con mi otra respuesta: no se puede utilizar dos veces en el mismo ámbito, ya que declara una variable. Sin embargo, todavía puede ser interesante para otro los casos en que desea tener somemacro foo ejecutar algo después foo.

#define my_macro \
    std::ostringstream oss; \
    for (int x=0; x<2; ++x) \
        if (x==1) ThreadSafeLogging(oss.str()); \
        else oss

int main() {
    my_macro << 1 << "hello world" << std::endl;
}

La configuración de registro que tengo es bastante similar:

bool ShouldLog(const char* file, size_t line, Priority prio);

class LoggerOutput : public std::stringstream {
public:
  LoggerOutput(const char* file, size_t line, Priority prio) 
  : prio(prio) 
  {
    Prefix(file, line, prio);
  }
  void Prefix(const char* file, size_t line, Priority prio);
  ~LoggerOutput() {
    Flush();
  }
  void Flush();
private:
  Priority prio;
};

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)

Si su registro está deshabilitado, el ostream nunca se creó y existe poca sobrecarga. Puede configurar el registro de nombre de archivo y número de línea (s) o niveles de prioridad. La función ShouldLog puede cambiar entre invocaciones, por lo que podría estrangular o salida límite. La salida del registro utiliza dos funciones para modificar en sí, Prefijo que añade un "archivo: Línea: (PRIO)" prefijo a la línea, y Flush () que a la vez vuelca a la salida del registro como un solo comando y añade una nueva línea a ella . En mi aplicación siempre lo hace, pero se puede hacer que el condicional si uno no está ya allí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top