2010-02-08 2 views
1

J'essaie de comprendre comment utiliser la bibliothèque Boost.Preprocessor http://www.boost.org/doc/libs/release/libs/preprocessor pour déplier un type "générique" pour différents types spécifiques. Ci-dessous, je vais demander ceci pour un simple exemple de classe de points. Compte tenu:Bibliothèque de préprocesseur Boost pour générer un ensemble de types basé sur une liste de types de base, par ex. PointI32, PointF32 etc en C++/CLI

struct Point##TYPE_SUFFIX_NAME 
{ 
    TYPE X; 
    TYPE Y; 

    // Other code 
}; 

Je veux générer ce type pour différents types de données de base (POD), par exemple:

PointF32, PointF64, PointI32 etc. 

où PointF32 serait:

struct PointF32 
{ 
    float X; 
    float Y; 
}; 

C'est basé sur un liste des types:

short, int, long, float, double etc. 

Je veux "déplier" le type ci-dessus pour ceux-ci. De préférence avec la définition "template" dans un fichier d'inclusion séparé et non pas en tant que macro, pour permettre un débogage plus facile.

REMARQUE: les modèles C++ ne m'intéressent pas. Je sais utiliser des gabarits. Mais ce ne sont pas utiles dans mon cas. A titre d'exemple, imaginez que ces types vont être utilisés à partir de .NET en C#, mais sont générés en C++/CLI. Alors, s'il vous plaît, tenez-vous à la question. Le problème, bien sûr, provient du manque de prise en charge des modèles dans .NET et du fait que les génériques ne sont pas adaptés pour résoudre mon problème.

+0

Juste pour m'assurer que je comprends la question. Ce que vous voulez faire est de définir une correspondance entre une liste de suffixes de type et une liste de types, et de laisser la magie du préprocesseur augmenter et de générer tous les types correspondants. Est-ce que c'est ça ? –

+0

Correct. Je pourrais ajouter que j'utilise Visual C++ 2008 avec Feature Pack. – nietras

Répondre

1

Sur la base de la réponse par Benoît Je suis venu avec la réponse suivante. La réponse se compose de trois fichiers:

  • MyPointTypes.h
  • MyPointTypeImpl.h
  • MyPointTypes.cpp

MyPointTypes.h:

#ifndef __MYSTRUCTURES_H__ 
#define __MYSTRUCTURES_H__ 

#include <boost/preprocessor/iteration/iterate.hpp> 
#include <boost/preprocessor/seq/size.hpp> 

typedef signed char int8; 
typedef unsigned char uint8; 
typedef signed short int16; 
typedef unsigned short uint16; 
typedef signed int int32; 
typedef unsigned int uint32; 
typedef signed int int64; 
typedef unsigned int uint64; 

typedef float float32; 
typedef double float64; 

#define MY_SIGNED_INTEGER_SEQ (int8)(int16)(int32)(int64) 
#define MY_SIGNED_INTEGER_SUFFIX_SEQ (I8)(I16)(I32)(I64) 

#define MY_UNSIGNED_INTEGER_SEQ (uint8)(uint16)(uint32)(uint64) 
#define MY_UNSIGNED_INTEGER_SUFFIX_SEQ (UI8)(UI16)(UI32)(UI64) 

#define MY_SIGNED_UNSIGNED_INTEGER_SEQ MY_SIGNED_INTEGER_SEQ MY_UNSIGNED_INTEGER_SEQ 
#define MY_SIGNED_UNSIGNED_INTEGER_SUFFIX_SEQ MY_SIGNED_INTEGER_SUFFIX_SEQ MY_UNSIGNED_INTEGER_SUFFIX_SEQ 

#define MY_FLOAT_SEQ (float32)(float64) 
#define MY_FLOAT_SUFFIX_SEQ (F32)(F64) 

#define MY_BASIC_NUMERIC_TYPES_SEQ MY_SIGNED_UNSIGNED_INTEGER_SEQ MY_FLOAT_SEQ 
#define MY_BASIC_NUMERIC_TYPES_SUFFIX_SEQ MY_SIGNED_UNSIGNED_INTEGER_SUFFIX_SEQ MY_FLOAT_SUFFIX_SEQ 


#define MY_SEQ_OF_TYPES MY_BASIC_NUMERIC_TYPES_SEQ 
#define MY_SEQ_OF_SUFFICES MY_BASIC_NUMERIC_TYPES_SUFFIX_SEQ 

#define BOOST_PP_ITERATION_LIMITS (0, BOOST_PP_SEQ_SIZE(MY_SEQ_OF_TYPES) - 1) 
#include BOOST_PP_ITERATE() 

#undef MY_SEQ_OF_TYPES 
#undef MY_SEQ_OF_SUFFICES 

#endif 

MyPointTypeImpl.h:

#include <boost/preprocessor/seq/elem.hpp> 

#define n BOOST_PP_ITERATION() 
#define PASTER(x,y) x ## y 
#define EVALUATOR(x,y) PASTER(x,y) 
#define CONCATEVALUATED(x, y) EVALUATOR(x, y) 

#define TYPE BOOST_PP_SEQ_ELEM(n, MY_SEQ_OF_TYPES) 
#define SUFFIX BOOST_PP_SEQ_ELEM(n, MY_SEQ_OF_SUFFICES) 

#define ADDSUFFIX(cls) CONCATEVALUATED(cls, SUFFIX) 

struct ADDSUFFIX(Point) 
{ 
    TYPE X; 
    TYPE Y; 
}; 

#undef n 

MyPointTypes.cpp:

#define BOOST_PP_FILENAME_1 "MyPointTypeImpl.h" 
#include "MyPointTypes.h" 

Cela définira les types:

PointI8, PointI16, PointI32, PointI64, 
PointUI8, PointUI16, PointUI32, PointUI64, 
PointF32, PointF64 

Imaginez alors au lieu d'un C++ struct un type de valeur C++/CLI ie: 01 Ensuite, nous avons effectivement créé des types de points de tous les types numériques de base pour une utilisation dans .NET, par exemple. C#.

+0

A +1 aurait été bien si –

1

Anciennes versions (pré-modèle) des compilateurs C++ avaient souvent un <generic.h> en-têtes pour ce genre de chose. Je rechercherais les anciennes versions de g ++ pour cela. C'était avant mon temps, donc je ne sais pas si cela te conviendrait ou non.

Sinon, quelque chose comme

#define TYPE short 
#define TYPES I16 
#include "Point.def" 
#undef TYPE 
#undef TYPES 
#define TYPE int 
#define TYPES I32 
#include "Point.def" 

pourrait aussi vous aider.

Ou bien évidemment un générateur de code externe (en awk, perl, C++, peu importe). Cela pourrait être la meilleure solution.

+0

Cette solution que je connaissais et n'était pas exactement ce que je cherchais. Cela fonctionne bien :) Voir ma propre réponse basée sur la réponse de Benoîts. – nietras

1

Le code suivant est non testé mais devrait être un bon début pour faire ce que vous voulez.

En my_structures.h:

#ifndef __MYSTRUCTURES_H__ 
#define __MYSTRUCTURES_H__ 

#define MY_LIST_OF_TYPES (F32, (I32, (BOOST_PP_NIL))) 
#define MY_LIST_OF_SUFFICES (float, (int, (BOOST_PP_NIL))) 

#include <boost/preprocessor/iteration/iterate.hpp> 
#include <boost/preprocessor/list/size.hpp> 

#define BOOST_PP_ITERATION_LIMITS (0, BOOST_PP_LIST_SIZE(MY_LIST_OF_TYPES)) 
#define BOOST_PP_FILENAME_1  "create_my_structures.h" 
#include BOOST_PP_ITERATE() 

#undef MY_LIST_OF_TYPES 
#undef MY_LIST_OF_SUFFICES 
#endif 

et create_my_structures.h

#include <boost/preprocessor/list/at.hpp> 

#define n BOOST_PP_ITERATION() 

struct Point ## BOOST_PP_LIST_AT(MY_LIST_OF_SUFFICES, n) 
{ 
    BOOST_PP_LIST_AT(MY_LIST_OF_TYPES, n) X; 
    BOOST_PP_LIST_AT(MY_LIST_OF_TYPES, n) Y; 
}; 

#undef n 
+0

Je reçois les erreurs suivantes à la place: avertissement C4003: pas assez de paramètres réels pour macro « BOOST_PP_LIST_FIRST_I » avertissement C4003: pas assez de paramètres réels pour macro « BOOST_PP_LIST_REST_I » Et il semble que la sortie de préprocesseur est quelque chose comme: classe de valeur publique Point ## I32 { int X; int Y; }; Le suffixe et le nom de la classe ne sont donc pas concaténés. Par conséquent, le code – nietras

+0

Ok, j'ai corrigé le problème de concaténation. Le nouveau create_my_structures.h est maintenant: #include #define n BOOST_PP_ITERATION() #define Paster (x, y) x ## y #define Evaluator (x, y) dérouleur (x, y) #define CONCATEVALUATED (x, y) d'analyse (x, y) #define SUFFIX BOOST_PP_LIST_AT (MY_LIST_OF_SUFFICES, n) #define TYPE BOOST_PP_LIST_AT (MY_LIST_OF_TYPES, n) #define ADDSUFFIX (cls) CONCATEVALUATED (cls, SUFFIX) structure ADDSUFFIX (Point) { TYPE X; TYPE Y; }; #undef n (il est regrettable que les commentaires ne puissent pas coller correctement le code). – nietras

+0

Peut-être, vous pourriez éditer votre réponse pour refléter ceci. Cependant, cela ne fonctionne toujours pas en raison des avertissements susmentionnés.Il semble qu'il se déroule aussi la terminaison et similaire: struct PointBOOST_PP_NIL { BOOST_PP_NIL X; BOOST_PP_NIL Y; }; struct PointBOOST_PP_LIST_FIRST_I { BOOST_PP_LIST_FIRST_I X; BOOST_PP_LIST_FIRST_I Y; }; – nietras

0

Cela semble une vieille question, mais je pense .... est plus facile de le faire juste avec le macroprocesseur standard (RPC)

#define STRUCT_POINT(P_TYPE) \ 
struct Point##_##P_TYPE  \ 
{        \ 
    P_TYPE X;     \ 
    P_TYPE Y;     \ 
           \ 
}; 

#define CREATE_STRUCT_POINTS \ 
    STRUCT_POINT(short )  \ 
    STRUCT_POINT(int  )  \ 
    STRUCT_POINT(unsigned)  \ 
    STRUCT_POINT(float )  \ 
    STRUCT_POINT(double ) 

CREATE_STRUCT_POINTS 

#undef CREATE_STRUCT_POINTS 
#undef STRUCT_POINT 

Ou peut-être cette variation (à suivre les « spécifications »)

#define STRUCT_POINT(P_TYPE, P_TYPE_ALIAS) \ 
struct Point##P_TYPE_ALIAS  \ 
{        \ 
    P_TYPE X;     \ 
    P_TYPE Y;     \ 
           \ 
}; 

#define CREATE_STRUCT_POINTS \ 
    STRUCT_POINT(short , I16 )  \ 
    STRUCT_POINT(int  , I32 )  \ 
    STRUCT_POINT(unsigned , U32 )  \ 
    STRUCT_POINT(float , F32 )  \ 
    STRUCT_POINT(double , F64 ) 

CREATE_STRUCT_POINTS 

#undef CREATE_STRUCT_POINTS 
#undef STRUCT_POINT 
+2

Eh bien, cela résout le problème (et c'est une solution que j'ai déjà utilisé), mais il a un certain nombre d'inconvénients. Le principal étant que le débogage de toutes les macros est rendu difficile car il n'y aura qu'une seule ligne de code. De plus, le code doit être déclaré comme une macro, ce qui le rend plus difficile à modifier, par rapport à l'approche par inclusion. – nietras

Questions connexes