1

問題:

私は可変個引数マクロを書きたいと思っています

#define WRAP(token, ...) 

これは、トークンと N 個の引数で呼び出された場合

WRAP(decltype, a, b, c)

トークンにラップされた引数のコンマ区切りリストに展開されます

decltype(a), decltype(b), decltype(c)

これにより、次のようなものを書くことができます。

#define MACRO(...) \
    Class< WRAP(decltype, __VA_ARGS__) >::Function();

次のように呼び出すと:

MACRO(a, b, c)

次のようになります。

Class<decltype(a), decltype(b), decltype(c)>::Function(0;

これを達成する方法がわかりません。出来ますか?おそらく、BOOST_PPまたはそのようなものでしょうか?

動機:

ログ用のマクロがあります:

#define LOG(fmt, ...) \
    logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);

引数が提供されたフォーマット文字列と一致することを確認できる可変個引数クラス テンプレートがあります。

template<typename... Ts>
struct Format
{
    template<std::size_t N>
    static constexpr bool check(const char (&fmt)[N], std::size_t n);
};

固定数の引数でマクロを定義すると、フォーマット チェック関数を呼び出すことができます。

#define LOG(fmt, a) \
    static_assert(Format<decltype(a1)>::check(fmt, 0), ""); \
    logger::instance().push(__FUNCTION__, fmt, a);

ただし、可変引数マクロを使用すると、これは複数の引数に対しては機能しません。

#define LOG(fmt, ...) \
    static_assert(Format<decltype(__VA_ARGS__)>::check(fmt, 0), ""); \
    logger::instance().push(__FUNCTION__, fmt, __VA_ARGS__);

これdecltype(__VA_ARGS__)は、明らかに無効な構文であるためです。

それを修正するには、展開する必要があり__VA_ARGS__ますdecltype(a1), decltype(a2), decltype(a3)

可変関数テンプレート?

constexpr可変引数関数テンプレートを使用してこれを達成しようとしましたが、この時点で文字列リテラルではなくなったためfmt、 a に渡すことができません。static_assert

template<size_t N, typename... Ts>
constexpr void check(const char (&fmt)[N], const Ts&...)
{
    static_assert(Format<Ts...>::check(fmt, 0), "");
}

このチェック関数を呼び出そうとしています

check("%s", "hello world"); 

コンパイルに失敗します:

main.cpp:216:46:   in constexpr expansion of ‘Format<T, Ts ...>::check<7ul>((* & fmt), 0ul)’
main.cpp:216:5: error: ‘fmt’ is not a constant expression
4

1 に答える 1

2

Boost.PP を使えばとても簡単です:

#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define COMMA_SEP(r, token, i, e) BOOST_PP_COMMA_IF(i) token(e)
#define WRAP(token, ...) BOOST_PP_SEQ_FOR_EACH_I(COMMA_SEP, token, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

編集: が空の場合、上記は機能しません。それを解決するには、このソリューション__VA_ARGS__を参照してください。の代わりに使用するだけです。BOOST_PP_IS_EMPTYISEMPTY

于 2015-03-24T05:23:37.933 に答える