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.
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#.