Search code examples
c++templatesmacrosmetaprogrammingboost-preprocessor

Varadiac macros for making different partial specialization of a class


For some classes we can define macros which does explicit template specialization as the folllowing example from Boost Serialization library:

#define BOOST_IS_BITWISE_SERIALIZABLE(T)              \
namespace boost {                                     \
namespace serialization {                             \
template<>                                            \
struct is_bitwise_serializable< T > : mpl::true_ {};  \
}}                                                    \
/**/

This works for full specialization like BOOST_IS_BITWISE_SERIALIZABLE(MyClass<int>)

But I would like to create a convenience macro that works for partial specialization with different arguments as following:

template<class T, class Enable>
struct is_bitwise_serializable< MyClassA<T, Enable> > : mpl::true_ {};

template<class T>
struct is_bitwise_serializable< MyClassB<T> > : mpl::true_ {};

template<int N>
struct is_bitwise_serializable< MyClassC<N> > : mpl::true_ {};

.....

I was trying to go through Boost PreProcessor documentation for this problem, but could not proceed a lot. Is it there a Boost PreProcessor solution for this?


Solution

  • Here is a solution which uses Boost.Preprocessor. It is built on the work with sequences.

    #include <boost/mpl/bool.hpp>
    #include <boost/preprocessor/cat.hpp>
    #include <boost/preprocessor/arithmetic/sub.hpp>
    #include <boost/preprocessor/seq/enum.hpp>
    #include <boost/preprocessor/seq/transform.hpp>
    #include <boost/preprocessor/seq/size.hpp>
    #include <boost/preprocessor/repetition/enum_params.hpp>
    
    
    #define PARAM_NAME param
    
    #define PARAM(Index) BOOST_PP_CAT(PARAM_NAME, Index)
    
    #define PARAM_DESCRIPTION(Index, Data, ParamType) \
        ParamType PARAM(BOOST_PP_SUB(Index, 2))
    
    #define IS_BITWISE_SERIALIZABLE(TemplateClass, Params) \
    template \
        < \
            BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(PARAM_DESCRIPTION,, Params)) \
        > \
    struct is_bitwise_serializable \
        < \
            TemplateClass \
                < \
                    BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(Params), PARAM_NAME) \
                > \
        > \
        : boost::mpl::true_ {};
    

    Example of using:

    template <class T, class Enable>
    struct MyClassA{};
    
    template <class T>
    struct MyClassB{};
    
    template <int N>
    struct MyClassC{};
    
    template <class T, template <class> class Base = MyClassB>
    struct MyClassD : public Base<T>{};
    
    
    IS_BITWISE_SERIALIZABLE(MyClassA, (class)(class))
    
    IS_BITWISE_SERIALIZABLE(MyClassB, (class))
    
    IS_BITWISE_SERIALIZABLE(MyClassC, (int))
    
    IS_BITWISE_SERIALIZABLE(MyClassD, (class)(template <class> class))
    

    See live example.