preprocesamiento - ¿Hay alguna forma de escribir lo siguiente como una macro de C++?
funcion preprocesador en c++ (7)
my_macro << 1 << "hello world" << blah->getValue() << std::endl;
debería expandirse en:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
¿No podría derivar de ostream y proporcionar su propia implementación segura de subprocesos? Entonces podrías hacer
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
¿Y obtiene exactamente la misma funcionalidad sin macros y usando C ++ correctamente?
Aquí hay otro truco desagradable que vi en otro lado. Tiene una desventaja significativa en comparación con mi otra respuesta: no puede usarla dos veces en el mismo ámbito porque declara una variable. Sin embargo, aún puede ser interesante para otros casos en los que quieras tener somemacro foo
ejecutando algo después de 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;
}
Echa un vistazo a google-glog , lo hacen usando un objeto temporal instanciado con un
LOG(INFO) << "log whatever" << 1;
y también tienen otras macros interesantes como LOG_IF et al.
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 crea y existe poca sobrecarga. Puede configurar el registro en nombre de archivo y número (s) de línea o niveles de prioridad. La función ShouldLog puede cambiar entre invocaciones, por lo que puede acelerar o limitar la salida. La salida de registro utiliza dos funciones para modificarse, Prefijo que agrega un prefijo "file: line: (PRIO)" a la línea y Flush () que lo vacía al resultado de registro como un solo comando y le agrega una nueva línea. . En mi implementación, siempre lo hace, pero puede hacer eso condicional si uno no está ya allí.
No. El problema es que sin utilizar la sintaxis de la función, una macro se limita a ser reemplazada solo donde está.
Pero si estaba dispuesto a usar la sintaxis de la función, puede reemplazar cosas tanto antes como después de los argumentos.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
Podrías definir MyMacro como:
#define my_macro(args) std::ostreamstring oss; /
oss << args; /
ThreadSafeLogging(oss.str());
Teniendo en cuenta que tiene estas líneas incluidas en algún lugar de su código, sí, es posible
#include <iostream>
#include <sstream>
__LINE__
macro está definido por todos los compiladores estándar. Entonces podemos usarlo para generar un nombre de variable que sea diferente cada vez que use la macro :)
Aquí hay una nueva versión que se ve solo como una instrucción de instrucción: (EDITADO)
#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;
}
Es probable que Developper no necesite usar esta macro dos veces en la misma línea debido a la simplicidad del operador <<
. Pero en caso de que lo necesite, puede cambiar el uso de __LINE__
por __COUNTER__
(que no es estándar). Gracias a Quuxplusone por este consejo
#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 de tipo my_stream
, que es una subclase de ostringstream
. Todas las operaciones a ese trabajo temporal como lo harían en un ostringstream
.
Cuando la instrucción finaliza (es decir, justo después del punto y coma de toda la operación de impresión en main ()), el objeto temporal sale del alcance y se destruye. El destructor my_stream
llama a ThreadSafeLogging
con los datos "recopilados" previamente.
Probado (g ++).
Gracias / créditos a dingo por señalar cómo simplificar todo, así que no necesito el operator<<
sobrecargado operator<<
. Las votaciones negativas demasiado malas no se pueden compartir.