2016-02-29 31 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)