119

このようなマクロがあるとしましょう

#define FOO(type,name) type name

どのように使用できますか

FOO(int, int_var);

しかし、必ずしもそれほど単純ではありません。

FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2

もちろん、次のことができます。

 typedef std::map<int, int> map_int_int_t;
 FOO(map_int_int_t, map_var); // OK

これは人間工学的ではありません。プラスタイプの非互換性に対処する必要があります。マクロでこれを解決する方法はありますか?

4

7 に答える 7

142

If you can't use parentheses and you don't like Mike's SINGLE_ARG solution, just define a COMMA:

#define COMMA ,

FOO(std::map<int COMMA int>, map_var);

This also helps if you want to stringify some of the macro arguments, as in

#include <cstdio>
#include <map>
#include <typeinfo>

#define STRV(...) #__VA_ARGS__
#define COMMA ,
#define FOO(type, bar) bar(STRV(type) \
    " has typeid name \"%s\"", typeid(type).name())

int main()
{
    FOO(std::map<int COMMA int>, std::printf);
}

which prints std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE".

于 2013-11-07T16:36:17.343 に答える
129

Because angle brackets can also represent (or occur in) the comparison operators <, >, <= and >=, macro expansion can't ignore commas inside angle brackets like it does within parentheses. (This is also a problem for square brackets and braces, even though those usually occur as balanced pairs.) You can enclose the macro argument in parentheses:

FOO((std::map<int, int>), map_var);

The problem is then that the parameter remains parenthesized inside the macro expansion, which prevents it being read as a type in most contexts.

A nice trick to workaround this is that in C++, you can extract a typename from a parenthesized type name using a function type:

template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);

Because forming function types ignores extra parentheses, you can use this macro with or without parentheses where the type name doesn't include a comma:

FOO((int), int_var);
FOO(int, int_var2);

In C, of course, this isn't necessary because type names can't contain commas outside parentheses. So, for a cross-language macro you can write:

#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif
于 2012-12-12T15:16:09.817 に答える
69

プリプロセッサが可変個引数マクロをサポートしている場合:

#define SINGLE_ARG(...) __VA_ARGS__
#define FOO(type,name) type name

FOO(SINGLE_ARG(std::map<int, int>), map_var);

そうでなければ、それはもう少し退屈です:

#define SINGLE_ARG2(A,B) A,B
#define SINGLE_ARG3(A,B,C) A,B,C
// as many as you'll need

FOO(SINGLE_ARG2(std::map<int, int>), map_var);
于 2012-12-12T15:08:00.453 に答える
37

Just define FOO as

#define UNPACK( ... ) __VA_ARGS__

#define FOO( type, name ) UNPACK type name

Then invoke it always with parenthesis around the type argument, e.g.

FOO( (std::map<int, int>), map_var );

It can of course be a good idea to exemplify the invocations in a comment on the macro definition.

于 2016-03-14T23:06:52.497 に答える
4

これを行うには、少なくとも2つの方法があります。まず、複数の引数を取るマクロを定義できます。

#define FOO2(type1, type2, name) type1, type2, name

そうすると、より多くの引数を処理するために、より多くのマクロを定義することになります。

次に、引数を括弧で囲むことができます。

#define FOO(type, name) type name
F00((std::map<int, int>) map_var;

そうすると、余分な括弧が結果の構文を台無しにすることに気付くかもしれません。

于 2012-12-12T15:08:18.043 に答える
4

This is possible with P99:

#include "p99/p99.h"
#define FOO(...) P99_ALLBUTLAST(__VA_ARGS__) P99_LAST(__VA_ARGS__)
FOO()

The code above effectively strips only the last comma in the argument list. Check with clang -E (P99 requires a C99 compiler).

于 2012-12-12T15:25:30.960 に答える
3

簡単な答えはあなたができないということです。<...>これは、テンプレート引数の選択の副作用です。<とは>不均衡なコンテキストでも表示されるため、括弧を処理するようにマクロメカニズムを拡張してそれらを処理することはできませんでした。(委員会のメンバーの中には、別のトークンを主張した人もいました(^...^)が、を使用して問題の大部分を納得させることができませんでした<...>。)

于 2012-12-12T15:11:33.110 に答える