views:

302

answers:

4

Hi, I am trying to figure out how to use the Boost.Preprocessor library http://www.boost.org/doc/libs/release/libs/preprocessor to unfold a "generic" type for different specific types. Below I will ask this for a simple point class example. Given:

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

    // Other code
};

I want to generate this type for different basic (POD) data types e.g.:

PointF32, PointF64, PointI32 etc.

where PointF32 would be:

struct PointF32
{
     float X;
     float Y;
};

That is, based on a list of types:

short, int, long, float, double etc. 

I want to "unfold" the above type for these. Preferably with the "template" definition in a separate include file and not as a macro, to allow for easier debugging.

NOTE: I am not interested in hearing about C++ templates. I know how to use templates. But these are not useful in my case. As an example imagine these types are going be used from .NET in C#, but are being generated in C++/CLI. So please stick to the question.

The problem, of course, stems from the lack of template support in .NET and due to generics not being suitable to solve my problem.

+1  A: 

Old (pre-template) versions of C++ compilers had often a <generic.h> headers for such kind of thing. I'd search old versions of g++ for it. It was before my time, so I don't know if it would suit you or not.

Alternatively, something like

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

could also help you.

Or obviously an external code generator (in awk, perl, C++, whatever). That could be the best solution.

AProgrammer
This solution I knew and wasn't exactly what I was looking for. It works though :) See my own answer based on Benoîts answer.
harrydev
+1  A: 

The following code is untested but should be a good start to make what you want happen.

In 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

and in 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
Benoît
I get the following errors instead:warning C4003: not enough actual parameters for macro 'BOOST_PP_LIST_FIRST_I'warning C4003: not enough actual parameters for macro 'BOOST_PP_LIST_REST_I'And it appears the output from preprocessor is something like:public value class Point ## I32{ int X; int Y;};so the suffix and class name are not concatenated.
harrydev
Ok I have fixed the concat problem. The new create_my_structures.h is now: #include <boost/preprocessor/list/at.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 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)struct ADDSUFFIX(Point){ TYPE X; TYPE Y;};#undef n( unfortunate that comments cannot have proper code pasting ).
harrydev
Maybe, you could edit your answer to reflect this. However, it still does not work due to the aforementioned warnings. It appears it also unfolds the termination and similar: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;};
harrydev
Hi, I finally figured out how to do it using a sequence instead of a list. I would like to post this as an answer, but this would mean that you (Benoît) will not get the honor of having answered, even though, you pretty much did. So is that ok with you?(Sorry for all the comments)
harrydev
Sure it's ok. I can also edit my answer if you want.
Benoît
+1  A: 

Based on the answer by Benoît I have come up with the following answer. The answer consists of three files:

  • 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"

This will define the types:

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

Imagine then instead of a C++ struct a C++/CLI value type i.e.:

public value class Point 

Then we have effectively created point types of all basic numeric types for use in .NET e.g. C#.

harrydev
A +1 would have been nice though
Benoît
A: 

This seems an old question but.... I think is easier to do it just with the standard macroprocessor (CPP)

#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

Or maybe this variation (to follow the 'specifications')

#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
Miguel Mesones
Well, this does solve the problem (and is a solution I already have been using) but it has a number of drawbacks. The primary being that since the is all macros debugging is made difficult since there will only be one line of code. Also the code has to be declared as a macro which makes it more difficult to edit, compared to the include approach.
harrydev