簡體   English   中英

C ++和預處理器宏:可變參數類型

[英]C++ and preprocessor macros: variadic type

以下面的宏為例:

#define _CREATE_VAR(X1) double X1{smc::define_variable (data, X1, #X1)};
#define _CREATE_VAR2(X1,X2) double X1{smc::define_variable (data, X1, #X1)}; /
                        double X2{smc::define_variable (data, X2, #X2)}; /
#define _CREATE_VAR3(X1,X2,X3) double X1{smc::define_variable (data, X1, #X1)}; /
                        double X2{smc::define_variable (data, X2, #X2)}; /
                        double X3{smc::define_variable (data, X3, #X3)}; /
#define _CREATE_VAR4(X1,X2,X3,X4) double X1{smc::define_variable (data, X1, #X1)}; /
                        double X2{smc::define_variable (data, X2, #X2)}; /
                        double X3{smc::define_variable (data, X3, #X3)}; /
                        double X4{smc::define_variable (data, X4, #X4)}; /
#define _CREATE_VAR5(X1,X2,X3,X4,X5) double X1{smc::define_variable (data, X1, #X1)}; /
                        double X2{smc::define_variable (data, X2, #X2)}; /
                        double X3{smc::define_variable (data, X3, #X3)}; /
                        double X4{smc::define_variable (data, X4, #X4)}; /
                        double X5{smc::define_variable (data, X5, #X5)}; /

有沒有一種方法可以通過使用一個宏_CREATE_VAR而不是讓多個實例具有不同的變量參數和相應的名稱來簡化此過程? 理想情況下,無論有多少個參數,我都希望自動調用同一宏_CREATE_VAR

如果您不介意調用語法略有不同,則可以使用boost.preprocessor

#include "boost/preprocessor.hpp"

// or to not include entire preprocessor header, the following header files will do
// #include <boost/preprocessor/stringize.hpp>
// #include <boost/preprocessor/seq/for_each.hpp>

#define CREATE_ONE_VAR(maR_, maData_, maVarName) \
  double maVarName {smc::define_variable (data, maVarName, BOOST_PP_STRINGIZE(maVarName))};

#define CREATE_VAR(maSeq) \
  BOOST_PP_SEQ_FOR_EACH(CREATE_ONE_VAR, %%, maSeq)

使用示例:

CREATE_VAR((x1)(x2)(x3))  //does the same as your original _CREATE_VAR3(x1, x2, x3)

現在,您可以使用從1到BOOST_PP_LIMIT_SEQ任意數量的變量來調用它,通常為256。

一些注意事項:我使用%%表示該參數未使用。 您可以在其中放置任何內容(將其傳遞給內部宏的maData參數,我們不使用它)。

您不應將宏命名為以下划線和大寫字母開頭。 根據標准,這是非法的,因為此類符號(以及包括兩個連續下划線的任何符號)都保留給編譯器使用。

做到這一點的方法之一是使用FOR_EACH宏觀__VA_ARGS__ ,它不漂亮,它可能需要一段時間才能完全伴隨着發生了什么,但至少它不依賴於跟隨boost

輔助宏:

// Concatenates tokens, even when the tokens are macros themselves.
#define PP_JOIN_HELPER_HELPER(_0, _1)       _0##_1
#define PP_JOIN_HELPER(_0, _1)              PP_JOIN_HELPER_HELPER(_0, _1)
#define PP_JOIN_IMPL(_0, _1)                PP_JOIN_HELPER(_0, _1)

#define PP_JOIN_2(_0, _1)                                                                   PP_JOIN_IMPL(_0, _1)
#define PP_JOIN_3(_0, _1, _2)                                                               PP_JOIN_2(PP_JOIN_2(_0, _1), _2)
#define PP_JOIN_4(_0, _1, _2, _3)                                                           PP_JOIN_2(PP_JOIN_3(_0, _1, _2), _3)
#define PP_JOIN_5(_0, _1, _2, _3, _4)                                                       PP_JOIN_2(PP_JOIN_4(_0, _1, _2, _3), _4)
#define PP_JOIN_6(_0, _1, _2, _3, _4, _5)                                                   PP_JOIN_2(PP_JOIN_5(_0, _1, _2, _3, _4), _5)
#define PP_JOIN_7(_0, _1, _2, _3, _4, _5, _6)                                               PP_JOIN_2(PP_JOIN_6(_0, _1, _2, _3, _4, _5), _6)
#define PP_JOIN_8(_0, _1, _2, _3, _4, _5, _6, _7)                                           PP_JOIN_2(PP_JOIN_7(_0, _1, _2, _3, _4, _5, _6), _7)
#define PP_JOIN_9(_0, _1, _2, _3, _4, _5, _6, _7, _8)                                       PP_JOIN_2(PP_JOIN_8(_0, _1, _2, _3, _4, _5, _6, _7), _8)
#define PP_JOIN_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)                                  PP_JOIN_2(PP_JOIN_9(_0, _1, _2, _3, _4, _5, _6, _7, _8), _9)
#define PP_JOIN_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10)                             PP_JOIN_2(PP_JOIN_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9), _10)
#define PP_JOIN_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)                        PP_JOIN_2(PP_JOIN_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10), _11)
#define PP_JOIN_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12)                   PP_JOIN_2(PP_JOIN_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11), _12)
#define PP_JOIN_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13)              PP_JOIN_2(PP_JOIN_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12), _13)
#define PP_JOIN_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14)         PP_JOIN_2(PP_JOIN_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13), _14)
#define PP_JOIN_16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15)    PP_JOIN_2(PP_JOIN_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14), _15)

// Chooses a value based on a condition.
#define PP_IF_0(t, f)           f
#define PP_IF_1(t, f)           t
#define PP_IF(cond, t, f)       PP_JOIN_2(PP_IF_, PP_TO_BOOL(cond))(t, f)

// Converts a condition into a boolean 0 (=false) or 1 (=true).
#define PP_TO_BOOL_0 0
#define PP_TO_BOOL_1 1
#define PP_TO_BOOL_2 1
#define PP_TO_BOOL_3 1
#define PP_TO_BOOL_4 1
#define PP_TO_BOOL_5 1
#define PP_TO_BOOL_6 1
#define PP_TO_BOOL_7 1
#define PP_TO_BOOL_8 1
#define PP_TO_BOOL_9 1
#define PP_TO_BOOL_10 1
#define PP_TO_BOOL_11 1
#define PP_TO_BOOL_12 1
#define PP_TO_BOOL_13 1
#define PP_TO_BOOL_14 1
#define PP_TO_BOOL_15 1
#define PP_TO_BOOL_16 1

#define PP_TO_BOOL(x)       PP_JOIN_2(PP_TO_BOOL_, x)

// Returns 1 if the arguments to the variadic macro are separated by a comma, 0 otherwise.
#define PP_HAS_COMMA(...)                           PP_HAS_COMMA_EVAL(PP_HAS_COMMA_ARGS(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#define PP_HAS_COMMA_EVAL(...)                      __VA_ARGS__
#define PP_HAS_COMMA_ARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16

// Returns 1 if the argument list to the variadic macro is empty, 0 otherwise.
#define PP_IS_EMPTY(...)                                                        \
    PP_HAS_COMMA                                                                \
    (                                                                           \
        PP_JOIN_5                                                           \
        (                                                                       \
            PP_IS_EMPTY_CASE_,                                              \
            PP_HAS_COMMA(__VA_ARGS__),                                      \
            PP_HAS_COMMA(PP_IS_EMPTY_BRACKET_TEST __VA_ARGS__),         \
            PP_HAS_COMMA(__VA_ARGS__ (~)),                                  \
            PP_HAS_COMMA(PP_IS_EMPTY_BRACKET_TEST __VA_ARGS__ (~))      \
        )                                                                       \
    )

#define PP_IS_EMPTY_CASE_0001           ,
#define PP_IS_EMPTY_BRACKET_TEST(...)   ,

// Retrieve the number of arguments handed to a variable-argument macro.
#define PP_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...)    N
#define PP_VA_NUM_ARGS(...) PP_VA_NUM_ARGS_HELPER(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

// Correctly handles the case of 0 arguments.
#define PP_NUM_ARGS(...)        PP_IF(PP_IS_EMPTY(__VA_ARGS__), 0, PP_VA_NUM_ARGS(__VA_ARGS__))

// Pass each variable in a VA_ARGS list to a macro.
#define PP_FE_0(action, X)
#define PP_FE_1(action, X) action(X)
#define PP_FE_2(action, X, ...) action(X)PP_FE_1(action, __VA_ARGS__)
#define PP_FE_3(action, X, ...) action(X)PP_FE_2(action, __VA_ARGS__)
#define PP_FE_4(action, X, ...) action(X)PP_FE_3(action, __VA_ARGS__)
#define PP_FE_5(action, X, ...) action(X)PP_FE_4(action, __VA_ARGS__)
#define PP_FE_6(action, X, ...) action(X)PP_FE_5(action, __VA_ARGS__)
#define PP_FE_7(action, X, ...) action(X)PP_FE_6(action, __VA_ARGS__)
#define PP_FE_8(action, X, ...) action(X)PP_FE_7(action, __VA_ARGS__)
#define PP_FE_9(action, X, ...) action(X)PP_FE_8(action, __VA_ARGS__)
#define PP_FE_10(action, X, ...) action(X)PP_FE_9(action, __VA_ARGS__)
#define PP_FE_11(action, X, ...) action(X)PP_FE_10(action, __VA_ARGS__)
#define PP_FE_12(action, X, ...) action(X)PP_FE_11(action, __VA_ARGS__)
#define PP_FE_13(action, X, ...) action(X)PP_FE_12(action, __VA_ARGS__)
#define PP_FE_14(action, X, ...) action(X)PP_FE_13(action, __VA_ARGS__)
#define PP_FE_15(action, X, ...) action(X)PP_FE_14(action, __VA_ARGS__)
#define PP_FE_16(action, X, ...) action(X)PP_FE_15(action, __VA_ARGS__)

#define PP_FOR_EACH(action, ...) PP_JOIN_2(PP_FE_, PP_NUM_ARGS(__VA_ARGS__))(action, __VA_ARGS__)

宏的定義:

#define CREATE_VAR(var)     double var{smc::define_variable(data, var, #var)};
#define CREATE_VARS(...)    PP_FOR_EACH(CREATE_VAR, __VA_ARGS__)

另外,您可能需要也可能不需要使用#pragma GCC system_header具體取決於您要編譯哪種警告lvl才能擺脫ISO C99 requires rest arguments to be used 您本可以使用#pragma GCC diagnostic ignored "-pedantic-errors"但顯然這是有問題的 如果您使用的是msvc,則必須找出警告以自行禁用。

這些稱為可變參數宏,可以聲明一個宏以接受可變數量的參數,就像函數可以接受的那樣。

聲明語法類似於可變參數函數的語法:省略號“ ...”用於表示必須傳遞一個或多個參數。 但是,通用編譯器還允許將零參數傳遞給此類宏。 在宏擴展期間,宏替換列表中每次出現的特殊標識符VA_ARGS都會被傳遞的參數替換。

例如C99方式,VC ++編譯器也支持。

#define FOO(fmt, ...) print(fmt, ##__VA_ARGS__)

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

這是一個簡單的用例,展示了如何使用vardiac maco,然后如何正確使用變量參數列表...而無需尋找其他庫!

也看看

http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

根據我對您問題的理解。 您應該使用省略號(...)。 我建議您通過以下鏈接進行檢查。 這是充分理解的幫助。

http://msdn.microsoft.com/en-us/library/ms177415(v=vs.80).aspx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM