Boost Preprocessorでコンストラクタ生成

今回は、下記のように記述すると、その下のコードのように展開してくれるマクロを、Boost Preprocessorを利用して作成してみたいと思います。(実際には改行は生成されません。)

struct Person {
    std::string FirstName;
    std::string LastName;
    int Age;

    CONSTRUCTOR(Person, FirstName, LastName, Age)
};
struct Person {
    std::string FirstName;
    std::string LastName;
    int Age;

    Person(decltype(FirstName) a_FirstName, decltype(LastName) a_LastName, decltype(Age) a_Age) 
        : FirstName(std::move(a_FirstName)), LastName(std::move(a_LastName)), Age(std::move(a_Age)) 
    {}
};


マクロ定義

Variadic引数をSEQに変換し、各要素をBOOST_PP_SEQ_TRANSFORMで変換したのちBOOST_PP_SEQ_ENUMで出力しています。(BOOST_PP_SEQ_ENUMはカンマ区切りで出力されます。)

通常のマクロでは結合はa_##memberのように記述しますが、Boost Preprocessorを利用している場合はBOOST_PP_CATを利用します。(同様に#memberはBOOST_PP_STRINGIZE(member)と記述します。)

#include <boost\preprocessor.hpp>

#define _CONSTRUCTOR_PARAM(s, data, member) \
    decltype(member) BOOST_PP_CAT(a_, member)

#define _CONSTRUCTOR_PARAMS(members) \
    BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(_CONSTRUCTOR_PARAM, , members))

#define _CONSTRUCTOR_INIT(s, data, member) \
    member(std::move(BOOST_PP_CAT(a_, member)))

#define _CONSTRUCTOR_INITS(members) \
    BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(_CONSTRUCTOR_INIT, , members))

#define _CONSTRUCTOR(cls, members) \
    cls(_CONSTRUCTOR_PARAMS(members)) : _CONSTRUCTOR_INITS(members) {}

#define CONSTRUCTOR(cls, ...) \
    _CONSTRUCTOR(cls, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))


展開結果の確認

cppファイルのプロパティで、Process to a Fileを有効化してファイルをコンパイルすると、出力フォルダに .i ファイルが生成されます。(.objファイルが出力されなくなるため、ビルド時には無効化してください。)

f:id:any-programming:20180116153641p:plain