2009-04-17 17 views
8

En vez de hacer lo siguiente cada vez queC++ # ¿define una macro con corchetes?

start(); 

// some code here 

stop(); 

Me gustaría definir algún tipo de macro que hace posible escribir como:

startstop() 
{ 

//code here 

} 

¿Es posible en C++?

Respuesta

40

Puede hacer algo muy cerca usando una pequeña clase de ayuda de C++.

class StartStopper { 
public: 
    StartStopper() { start(); } 
    ~StartStopper() { stop(); } 
}; 

Luego en el código:

{ 
    StartStopper ss; 
    // code here 
} 

Cuando la ejecución entra en el bloque y construye la variable ss, se llamará a la función start(). Cuando la ejecución abandona el bloque, se llamará automáticamente al destructor StartStopper y luego llamará al stop().

+12

+1. Este enfoque es sólido como una roca. Incluso si se lanza una excepción, se seguirá llamando a stop(), ya que C++ garantiza que los destructores siempre son llamados en la salida del alcance. –

+1

También evita problemas difíciles de solucionar que pueden ocurrir con las macros. –

+0

+1. La conversación en la respuesta de dirkgently es intrigante, pero esta es la mejor solución porque no crea un "macro lenguaje secreto". –

14

La forma idiomática de hacer esto en C++ se llama Resource Acquisition Is Initialization, o en breve RAII. Además de proporcionar lo que desea, también tiene el beneficio adicional de ser una excepción segura: se llamará a la función stop incluso si su código arroja una excepción.

definir una estructura de protección:

struct startstop_guard 
{ 
    startstop_guard() 
    { 
     start(); 
    } 
    ~startstop_guard() 
    { 
     stop(); 
    } 
}; 

y luego volver a escribir el código de la siguiente manera:

{ 
    startstop_guard g; 
    // your code 
} 

destructor del guardia (y por lo tanto la función stop) se llamará automáticamente al final de la bloque que lo rodea

+0

+1. ¡RAII! ¡RAII! ¡RAII! :) –

+0

Oye, no es necesario por fin :) – Skurmedel

1

¿Qué estás tratando de hacer? Recomiendo ver RAII como una forma mucho más orientada a C++ de hacer cosas que macro hacking, con todas sus consecuencias imprevistas.

4
#define startstop(x, y, ...) for(/* use macro args */) 
+0

+1, incluso si no es que muchas personas entenderán la inyección de dependencia allí ... –

+1

-1 para la implementación incompleta y poco clara. –

+0

@Iraimbilanja: ¿Qué no está claro y qué es incompleto? La pregunta no especifica nada sobre start() o stop(). – dirkgently

1

No utilice macros. Puede usar funciones en línea, ya que proporciona verificación de tipos y otras funciones. Puede consultar aquí: inline functions

+0

-1 las funciones en línea son completamente irrelevantes. –

2

Solución genérica con función RAII y boost :: (std :: function).

class starter 
{ 
    typedef boost::function< void() > action; 
    action end_; 
public: 
    starter(action start, action end): 
     end_(end) 
    { 
     log("starter start"); 
     start(); 
    } 
    ~starter() 
    { 
     log("starter end"); 
     end_() ; 
    } 
}; 
int main() 
{ 
    { 
     starter s(start, stop); 
     middle(); 
    } 

    return 0; 
} 

o para probar y comprobar la idea

void print(const std::string& message) 
    { 
     std::cout << message << std::endl; 
    } 
    int main() 
    { 
     starter s(boost::bind(print, "globalstart"), 
        boost::bind(print, "globalend")); 

     { 
      starter s(boost::bind(print, "start"), 
         boost::bind(print, "end")); 
      std::cout << "middle" << std::endl; 
     } 
     return 0; 
    } 
+0

+1 Buena implementación de protectores con ámbito que utilizan la función boost ::, se puede combinar con la inyección de dependencia en una macro para un uso más natural. –

5

Otras respuestas han abordado el lado RAII de la cuestión y, por lo voy a abordar el lado de la sintaxis que.

#define startstop for(Starter s; s.loop; s.loop = false) 
struct Starter { 
    bool loop; 
    Starter() { start(); loop = true; } 
    ~Starter() { stop(); } 
}; 

utilizado como:

startstop { 
    // some code 
} 

Debería explicarse por sí mismo suficiente.

+0

de hecho, quería escribir exactamente eso también. también podría hacer #define startstop() si (...) ..., lo que tendría el beneficio de no tocar cosas como int startstop = 1; y así. es decir, una macro de función necesitaría que los parientes hicieran la sustitución, lo que sería más seguro (y también correspondería directamente a sus deseos, y permitiría, además, empujar los argumentos hacia el ctor del principiante). pero todavía obtienes +1, por supuesto :) –

+0

Sí, buen punto. –

+0

otra cosa: a partir de C++ 03, el compilador puede tomar una copia de Starter() y enlazar la referencia a esa copia. eso significa que crearía dos objetos (uno explícitamente y otro creado por el compilador para vincular la referencia). usted, similar a la implementación de scope_guard de alexandrescu, necesita introducir una variable booleana mutable que establezca en falso (rhs.bool_var) por un cctor y true en el ctor predeterminado, y esto-> bool_var por el cctor. solo si es verdadero call end()) –

0

En C#, puede usar el patrón IDisposable e implementar su funcionalidad Stop() en el método Dispose(), pero eso funcionaría si estuviera usando una variante .net de C++.

+0

eh, además de estar fuera del tema, C++/CLI ni siquiera tiene la construcción using() de C#. –

1

crédito para dirkgently a la idea .. pensé que llenar el resto de

#define startstop() for(start();isStarted();stop())