C/C++ 宏中的逗号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13842468/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:45:55  来源:igfitidea点击:

Comma in C/C++ macro

c++cmacrosc-preprocessor

提问by PoP

Say we have a macro like this

假设我们有一个这样的宏

#define FOO(type,name) type name

Which we could use like

我们可以使用像

FOO(int, int_var);

But not always as simply as that:

但并不总是那么简单:

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

Of course we could do:

我们当然可以这样做:

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

which is not very ergonomic. Plus type incompatibilities have to be dealt with. Any idea how to resolve this with macro ?

这不是很符合人体工程学。必须处理 Plus 类型的不兼容性。知道如何用宏解决这个问题吗?

回答by not-a-user

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

如果您不能使用括号并且您不喜欢 Mike 的 SINGLE_ARG 解决方案,只需定义一个逗号:

#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".

打印std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE".

回答by ecatmur

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:

因为尖括号也可以表示(或出现在)比较运算符<, >, <=and >=,所以宏扩展不能像括号内那样忽略尖括号内的逗号。(这对于方括号和大括号也是一个问题,即使它们通常以平衡对的形式出现。)您可以将宏参数括在括号中:

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:

解决此问题的一个好技巧是,在 C++ 中,您可以使用函数类型从带括号的类型名称中提取类型名称:

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:

当然,在 C 中,这不是必需的,因为类型名称不能在括号外包含逗号。因此,对于跨语言宏,您可以编写:

#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

回答by Mike Seymour

If your preprocessor supports variadic macros:

如果您的预处理器支持可变参数宏:

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

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

Otherwise, it's a bit more tedious:

否则,它有点乏味:

#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);

回答by Cheers and hth. - Alf

Just define FOOas

只需定义FOO

#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.

在宏定义的注释中举例说明调用当然是一个好主意。

回答by xiaq

This is possible with P99:

这可以通过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).

上面的代码仅有效地去除了参数列表中的最后一个逗号。检查clang -E(P99 需要 C99 编译器)。

回答by Pete Becker

There are at least two ways to do this. First, you can define a macro that takes multiple arguments:

至少有两种方法可以做到这一点。首先,您可以定义一个带有多个参数的宏:

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

if you do that you may find that you end up defining more macros to handle more arguments.

如果你这样做,你可能会发现你最终定义了更多的宏来处理更多的参数。

Second, you can put parentheses around the argument:

其次,您可以在参数周围加上括号:

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

if you do that you may find that the extra parentheses screw up the syntax of the result.

如果你这样做,你可能会发现额外的括号搞砸了结果的语法。

回答by James Kanze

The simple answer is that you can't. This is a side effect of the choice of <...>for template arguments; the <and >also appear in unbalanced contexts so the macro mechanism couldn't be extended to handle them like it handles parentheses. (Some of the committee members had argued for a different token, say (^...^), but they weren't able to convince the majority of the problems using <...>.)

简单的答案是你不能。这是<...>模板参数选择的副作用;在<>也出现在不平衡背景下这样的宏观机制无法扩展到处理他们喜欢它处理括号。(例如,一些委员会成员曾主张使用不同的标记(^...^),但他们无法说服使用 的大多数问题<...>。)