2016-02-29 4 views
1

Я получил следующие макросыМакро не расширяется с прямым вызовом, но и расширена с непрямой

#include <boost/preprocessor.hpp> 

#define DB_FIELD(...) BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) 

#define DB_TOFIELD(type,name) \ 
    private:\ 
    type name##_;\ 
    public:\ 
    const type& get_##name(){return name##_;}\ 
    void set_##name(const type& val) { name##_ = val; } 

#define GEN_ENUM_FIELD(r,data,elem) BOOST_PP_CAT(FIELD_,BOOST_PP_SEQ_ELEM(1,elem)), 

#define DECLARE(type, name) DB_TOFIELD(type, name) 

#define GEN_FIELD_DECL(r, data, elem) DECLARE(BOOST_PP_SEQ_ELEM(0,elem),BOOST_PP_SEQ_ELEM(1,elem)) 

#define DB_TABLE(name, ...) class name : public DataBaseTable {\ 
    public:\ 
    constexpr static const char *get_table_name() { return #name; }\ 
    BOOST_PP_LIST_FOR_EACH(GEN_FIELD_DECL,, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) \ 
    enum Fields{ \ 
    BOOST_PP_LIST_FOR_EACH(GEN_ENUM_FIELD,, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))\ 
    FIELD_COUNT\ 
    };\ 
    }; 

Теперь следующий код:

DB_TABLE(Test2, 
    DB_FIELD(int, foo), 
    DB_FIELD(int, bar) 
) 

Формирует:

class Test2 : public DataBaseTable { 
public: 
    constexpr static const char *get_table_name() { return "Test2"; } 
private: 
    int foo_; 
public: 
    const int &get_foo() { return foo_; } 
    void set_foo(const int &val) { foo_ = val; } 
private: 
    int bar_; 
public: 
    const int &get_bar() { return bar_; } 
    void set_bar(const int &val) { bar_ = val; } 
    enum Fields { FIELD_foo, FIELD_bar, FIELD_COUNT }; 
}; 

Какие так же некрасиво, как я его написал, но моя забота - , почему мне нужен этот уровень косвенности (DECLARE) в макросе GEN_FIELD_DECL? Прямой вызов DB_TOFIELD

#define GEN_FIELD_DECL(r, data, elem) DB_TOFIELD(BOOST_PP_SEQ_ELEM(0,elem),BOOST_PP_SEQ_ELEM(1,elem)) 

производит мусор:

class Test2 : public DataBaseTable { 
public: 
    constexpr static const char *get_table_name() { return "Test2"; } 
private: 
    int foo _; 
public: 
    const int &get_BOOST_PP_SEQ_ELEM(1, (int)(foo))() { return foo _; } 
    void set_BOOST_PP_SEQ_ELEM(1, (int)(foo))(const int &val) { foo _ = val; } 
private: 
    int bar _; 
public: 
    const int &get_BOOST_PP_SEQ_ELEM(1, (int)(bar))() { return bar _; } 
    void set_BOOST_PP_SEQ_ELEM(1, (int)(bar))(const int &val) { bar _ = val; } 
    enum Fields { FIELD_foo, FIELD_bar, FIELD_COUNT }; 
}; 

Такое же поведение воспроизводится с лязгом 3.7.1 и GCC 5.3

ответ

2

То, что вы работаете в это исключение как препроцессор расширяет параметры, если они являются аргументами для операторов # или ##. От C++ 2011 § 16.3.1 ¶ 1:.

После аргументов для вызова функции, как макро, были определены, аргумент замена происходит. Параметр в списке замены, если не предшествует # или ## предварительной обработки маркера или с последующей ## предварительной обработки маркер (смотри ниже), заменяется соответствующим аргументом после всех макросов , содержащихся в нем, были расширены. Перед заменой токены предварительной обработки каждого аргумента полностью заменены макросами, как если бы они составляли остальную часть файла предварительной обработки; нет других токенов предварительной обработки .

Макро-косвенное исключение исключает предложение исключения, в результате чего аргумент будет расширен до того, как будет обработан другим макросом.

Например:

#define FOO 10 
#define BAR(x) x ## 7 
#define BAR2(x) BAR(x) 

int x = BAR(FOO);  // => int x = FOO7; 

int y = BAR2(FOO);  // => int y = BAR(10); (intermediate result) 
         // => int y = 107;  (final expansion)