Search code examples
.netboostc++-cliboost-preprocessor

Boost Preprocessor library for generating a set of types based on a list of basic types e.g. PointI32, PointF32 etc. in C++/CLI


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.


Solution

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