2010-06-06 5 views
2
void main() 
{ 
    int xyz = 123; // original value 
    { // code block starts 
     xyz++; 
     if(xyz < 1000) 
      xyz = 1; 
    } // code block ends 
    int original_value = xyz; // should be 123 
} 

void main() 
{ 
    int xyz = 123; // original value 
    MACRO_NAME(xyz = 123) // the macro takes the code code that should be executed at the end of the block. 
    { // code block starts 
     xyz++; 
     if(xyz < 1000) 
      xyz = 1; 
    } // code block ends << how to make the macro execute the "xyz = 123" statement? 
    int original_value = xyz; // should be 123 
} 

Seul le premier main() fonctionne.
Je pense que les commentaires expliquent le problème.MACRO C++ qui va exécuter un bloc de code et une certaine commande après ce bloc

Il n'a pas besoin d'être une macro mais pour moi, cela ressemble à un cas classique "macro-nécessaire". Au fait, il y a la macro/bibliothèque BOOST_FOREACH et je pense que c'est exactement la même chose que j'essaie de réaliser mais c'est trop complexe pour moi de trouver l'essence de ce dont j'ai besoin.
A partir de sa page de manuel d'introduction, un exemple:

#include <string> 
#include <iostream> 
#include <boost/foreach.hpp> 

int main() 
{ 
    std::string hello("Hello, world!"); 

    BOOST_FOREACH(char ch, hello) 
    { 
     std::cout << ch; 
    } 

    return 0; 
} 
+0

Pourquoi voulez-vous faire cela de toute façon? –

+0

J'ai un objet qui a un pointeur. J'ai besoin de changer temporairement ce pointeur, ainsi, le renvoyer à sa valeur originale, et je voudrais être automatisé, au lieu de "oublier". Aucun destructeur n'est voulu car cet objet reçoit la fonction, et devrait être retourné comme donné. – Poni

+0

Vous obtenez de mauvais résultats parce que vous utilisez 'void main()'. La fonction 'main' renvoie un' int', toujours. Tout le reste est un comportement indéfini. –

Répondre

8

La propre façon de le faire est probablement d'utiliser un conteneur RAII pour réinitialiser la valeur:

// Assumes T's assignment does not throw 
template <typename T> struct ResetValue 
{ 
    ResetValue(T& o, T v) : object_(o), value_(v) { } 
    ~ResetValue() { object_ = value_; } 

    T& object_; 
    T value_; 
}; 

utilisé comme:

{ 
    ResetValue<int> resetter(xyz, 123); 
    // ... 
} 

Lorsque le bloc se termine, le destructeur sera appelé, réinitialisant l'objet à la valeur spécifiée.

Si vous vraiment voulez utiliser une macro, tant qu'il est une expression relativement simple, vous pouvez le faire en utilisant un pour bloc:

for (bool b = false; b == false; b = true, (xyz = 123)) 
{ 
    // ... 
} 

qui peut être transformé en une macro:

#define DO_AFTER_BLOCK(expr) \ 
    for (bool DO_AFTER_BLOCK_FLAG = false; \ 
     DO_AFTER_BLOCK_FLAG == false; \ 
     DO_AFTER_BLOCK_FLAG = true, (expr)) 

utilisé comme:

DO_AFTER_BLOCK(xyz = 123) 
{ 
    // ... 
} 

Je ne sais vraiment pas t hink l'approche macro est une bonne idée; Je le trouverais probablement confus si je le voyais dans le code source de la production.

+0

Brilliant !! Merci beaucoup! .. et merci à tous ceux qui ont essayé! – Poni

+0

Avec un peu de supercherie (classe de base non-template 'ResetValueBase', un typedef pour' ResetValueBase const & 'et une fonction d'aide de modèle' ResetValue reset (T &, T) 'vous n'avez pas besoin de passer dans le type de la valeur En gros, vous écrivez 'ResetValueBase const & resetter = réinitialiser (xyz, 123);' – MSalters

+0

En fait, la solution macro de James est la réponse, à ma question spécifique au moins. – Poni

2

Vous n'avez pas absolument besoin d'une macro - vous pouvez utiliser des variables de portée interne:

#include <stdio.h> 
int main(void) 
{ 
    int xyz = 123; 
    printf("xyz = %d\n", xyz); 
    { 
     int pqr = xyz; 
     int xyz = pqr; 
     printf("xyz = %d\n", xyz); 
     xyz++; 
     if (xyz < 1000) 
      xyz = 1; 
     printf("xyz = %d\n", xyz); 
    } 
    printf("xyz = %d\n", xyz); 
    return(0); 
} 

Cela produit la sortie:

xyz = 123 
xyz = 123 
xyz = 1 
xyz = 123 

Si vous compilez avec GCC et -Wshadow vous obtenez un avertissement ; sinon, il compile propre. Vous ne pouvez pas écrire int xyz = xyz; dans le bloc interne de manière fiable; une fois que le '=' est analysé, la déclaration est complète et donc l'initialiseur est le 'xyz' interne, pas l'externe. La danse à deux pas fonctionne, cependant. Le principal défaut de ceci est qu'il nécessite une modification dans le bloc de code.

S'il y a des effets secondaires dans le bloc - comme les instructions d'impression ci-dessus - vous pouvez appeler une fonction qui contient le bloc interne. S'il n'y a pas d'effets secondaires dans le bloc, pourquoi l'exécutez-vous?

#include <stdio.h> 
static void inner(int xyz) 
{ 
    printf("xyz = %d\n", xyz); 
    xyz++; 
    if (xyz < 1000) 
     xyz = 1; 
    printf("xyz = %d\n", xyz); 
} 

int main(void) 
{ 
    int xyz = 123; 
    printf("xyz = %d\n", xyz); 
    inner(xyz); 
    printf("xyz = %d\n", xyz); 
    return(0); 
} 
0

Vous ne pouvez pas faire une macro exécuter une commande après une boucle à moins que vous mettez la boucle dans la macro. Et sérieusement? Ce serait une bien meilleure idée juste de faire une variable étendue.Garanti dans les cas d'exception, etc, alors que la version macro ne l'est certainement pas. Je préférerais utiliser ce modèle pour les garanties d'exception, et parce qu'il est plus flexible que de simplement copier l'int.

Questions connexes