web-dev-qa-db-fra.com

Définition macro contenant #include directive

Y a-t-il un moyen de définir une macro contenant un #include directive dans son corps?

Si je viens de mettre le "#include ", cela donne l'erreur

C2162: "expected macro formal parameter"

depuis ici, je n'utilise pas # Pour concaténer des cordes.
[.____] Si j'utilise "\# include ", alors je reçois les deux erreurs suivantes:

error C2017: illegal escape sequence
error C2121: '#' : invalid character : possibly the result of a macro expansion

De l'aide?

34
Bing Jian

Donc, comme les autres disent, non, vous ne pouvez pas avoir #include des déclarations dans une macro, car le préprocesseur ne passe qu'un seul passage. Cependant, vous pouvez faire du préprocesseur fondamentalement la même chose avec une astuce noueuse que je me suis retrouvée en utilisant récemment.

Réalisez que les directives de préprocesseur ne feront rien dans une macro, mais ils feront quelque chose dans un fichier. Donc, vous pouvez coller un bloc de code que vous souhaitez muter dans un fichier, en pensant à celle d'une définition macro (avec des pièces pouvant être modifiées par d'autres macros), puis #incluez ce fichier pseudo-macro dans divers endroits (faire Bien sûr, il n'y a pas de gardes!). Cela ne se comporte pas exactement comme une macro, mais cela peut atteindre de jolis résultats de type macro, car #include vient fondamentalement le contenu d'un fichier dans un autre.

Par exemple, envisagez d'inclure beaucoup d'en-têtes nommés de la même manière qui viennent en groupe. Il est fastidieux de les écrire tous, ou peut-être même ils sont générés automatiquement. Vous pouvez automatiser partiellement leur inclusion en faisant quelque chose comme ceci:

Helper Macros en-tête:

/* tools.hpp */

#ifndef __TOOLS_HPP__
#def __TOOLS_HPP__

// Macro for adding quotes
#define STRINGIFY(X) STRINGIFY2(X)    
#define STRINGIFY2(X) #X

// Macros for concatenating tokens
#define CAT(X,Y) CAT2(X,Y)
#define CAT2(X,Y) X##Y
#define CAT_2 CAT
#define CAT_3(X,Y,Z) CAT(X,CAT(Y,Z))
#define CAT_4(A,X,Y,Z) CAT(A,CAT_3(X,Y,Z))
// etc...

#endif

Fichier pseudo-macro

/* pseudomacro.hpp */

#include "tools.hpp"
// NO INCLUDE GUARD ON PURPOSE
// Note especially FOO, which we can #define before #include-ing this file,
// in order to alter which files it will in turn #include.
// FOO fulfils the role of "parameter" in this pseudo-macro.

#define INCLUDE_FILE(HEAD,TAIL) STRINGIFY( CAT_3(HEAD,FOO,TAIL) )

#include INCLUDE_FILE(head1,tail1.hpp) // expands to #head1FOOtail1.hpp
#include INCLUDE_FILE(head2,tail2.hpp)
#include INCLUDE_FILE(head3,tail3.hpp)
#include INCLUDE_FILE(head4,tail4.hpp)
// etc..

#undef INCLUDE_FILE

Fichier source

/* mainfile.cpp */

// Here we automate the including of groups of similarly named files

#define FOO _groupA_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupA_tail1.hpp"
// #include "head2_groupA_tail2.hpp"
// #include "head3_groupA_tail3.hpp"
// #include "head4_groupA_tail4.hpp"
#undef FOO

#define FOO _groupB_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupB_tail1.hpp"
// #include "head2_groupB_tail2.hpp"
// #include "head3_groupB_tail3.hpp"
// #include "head4_groupB_tail4.hpp"
#undef FOO

#define FOO _groupC_
#include "pseudomacro.hpp"
#undef FOO

// etc.

Celles-ci incluent même au milieu des blocs de codes que vous souhaitez répéter (avec FOO modifié), comme la réponse en Bing Jian demande: Définition macro contenant #include directive

Je n'ai pas largement utilisé ce truc, mais ça fait mon travail. Il peut évidemment être étendu à avoir autant de "paramètres" que nécessaire et vous pouvez exécuter les commandes de préprocesseur que vous aimez là-bas, ainsi que de générer du code réel. Vous ne pouvez tout simplement pas utiliser les choses que cela crée comme entrée dans une autre macro, comme vous le pouvez avec des macros normales, car vous ne pouvez pas coller l'inclure dans une macro. Mais cela peut aller à l'intérieur d'une autre pseudo-macro :).

D'autres pourraient avoir des commentaires sur d'autres limitations et ce qui pourrait se tromper :).

21
Ben Farmer

Je ne discuterai pas des mérites pour cela, mais Freeetype (www.freetype.org) procède aux éléments suivants:

#include FT_FREETYPE_H

où ils définissent ft_freetype_h ailleurs

13
Dan Hewett

Je crois que le préprocesseur C/C++ fait un seul passage sur le code, donc je ne pense pas que cela fonctionnerait. Vous pourrez peut-être obtenir un "#include" pour être placé dans le code par la macro, mais le compilateur s'étoufferait, car il ne sait pas quoi faire avec ça. Pour ce que vous essayez de faire pour travailler, le préprocesseur devra faire une seconde passe sur le fichier afin de ramasser le #include.

5
Herms

Je voulais aussi faire cela, et voici la raison:

Certains fichiers d'en-tête (notamment MPI.H dans OpenMPI) fonctionnent différemment si vous compilez en C ou C++. Je suis en train de relier à un C MPI code de mon programme C++. Pour inclure l'en-tête, je fais habituellement:

extern "C" {
#include "blah.h"
}

Mais cela ne fonctionne pas parce que __cplusplus est toujours défini même dans la liaison C. Cela signifie mpi.h, qui est inclus par bla.h, démarre la définition des modèles et le compilateur meurt indiquant que vous ne pouvez pas utiliser de modèles avec une liaison C.

Par conséquent, ce que je dois faire en bla.h est de remplacer

#include <mpi.h>

avec

#ifdef __cplusplus
#undef __cplusplus
#include <mpi.h>
#define __cplusplus
#else
#include <mpi.h>
#endif

Remarquablement, ce n'est pas seulement MPI.h qui fait cette chose pathologique. Par conséquent, je veux définir une macro INCLUDE_AS_C qui fait ce qui précède pour le fichier spécifié. Mais je suppose que ça ne marche pas.

Si quelqu'un peut comprendre une autre façon de l'accomplir, merci de me le faire savoir.

4
Lutorm

Je pense que vous êtes tous bien dans la mesure où cette tâche semble impossible comme je l'ai aussi de

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/03d20d234539A85C#

Non, les directives de préprocesseur en C++ (et C) ne sont pas réfléchissantes.

Pawel Dziepak

Quoi qu'il en soit, la raison de cette tentative est que j'essaie d'effectuer la suivante à plusieurs reprises utilisée l'extrait de code comme macro:

void foo(AbstractClass object)
{
    switch (object.data_type())
    {
    case AbstractClass::TYPE_UCHAR :
        {
        typedef unsigned char PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    case AbstractClass::TYPE_UINT:
        {
        typedef unsigned int PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    default:
        break;
    }
}

Pour une autre tâche, j'ai besoin d'avoir une fonction similaire

void bar(AbstractClass object)

où je vais placer

#include "snippets/bar.cpp"

et bien sûr, il est dans "Snippets/foo.cpp" et "Snippets/Bar.cpp" que le code spécifique à la tâche est écrit.

3
Bing Jian

Pourquoi la macro aurait-elle besoin d'avoir un #include? Si vous êtes # incluant le fichier de la macro, vous pouvez simplement mettre le #include au-dessus de la macro avec tout le reste des déclarations #include, et tout devrait être gentil et dandy.

Je ne vois aucune raison d'avoir la macro incluent tout ce qui ne pouvait être simplement inclus dans le fichier.

1
helloandre

Je n'ai aucune idée de ce que vous essayez réellement de faire, mais cela ressemble à ce que vous voudrez peut-être est une fonction modélisée.

De cette façon, le pixeltype est juste un paramètre de modèle au bloc de code.

0
user21714