hut*_*rny 5 c++ parameters templates arguments c-preprocessor
如图所示,如果将具有多个参数的模板实例化作为参数传递给宏,则C++预处理器将失败.
请参阅下面的示例.
#include <stdio.h>
#define FOO(v) printf("%d\n",v::val())
template<int N>
struct bar {
static int val() { return N; }
};
template<int N, int M>
struct baz {
static int val() { return N+M; }
};
int main() {
printf("%d\n",bar<1>::val());
printf("%d\n",baz<1,2>::val());
FOO(bar<10>); // OK
FOO(baz<20,30>); // error: too many arguments provided to function-like macro invocation
FOO((baz<20,30>)); // error: '::val' has not been declared
}
Run Code Online (Sandbox Code Playgroud)
用clang ++和g ++ 测试
它应该被视为一个错误吗?
Chr*_*eck 11
不,这不是一个错误.
c预处理器与语言的其他部分不同,它按照自己的规则播放.改变这种情况会大大破坏兼容性,CPP的标准化程度非常高.
解决这些逗号问题的常用方法是,
typedef baz<20,30> baz2030_type;
FOO(baz2030_type);
Run Code Online (Sandbox Code Playgroud)
C/C++ 预处理器将逗号识别为宏参数分隔符,除非它们嵌套在括号内。只是括号。方括号、大括号和模板标记不计算在内:
列表中的各个参数由逗号预处理标记分隔,但匹配内括号之间的逗号预处理标记不会分隔参数。(C++14 §16.3/11;C11 §6.10.3/11)
(上述的副作用是您可以使用不平衡的大括号和方括号作为宏参数。这通常不是一个好主意,但如果必须的话您可以这样做。)
结果偶尔会出现问题;当参数应该是一个代码块时,常见的一个是不需要的多个参数:
MY_FANCY_MACRO(1000, { int i=0, j=42; ... })
Run Code Online (Sandbox Code Playgroud)
在这里,使用(至少)3 个参数调用宏,尽管它可能被编写为接受 2 个。
使用现代 C++(和 C)编译器,您有多种选择。按照相当主观的顺序:
将宏重写为内联函数。如果参数是代码块,请考虑使用可以接受 lambda 或其他函子的模板化函数。如果参数是类型,请将其改为模板参数。
如果用多余的括号包围参数在语法上是有效的,那么就这样做。但在这种情况下,几乎可以肯定上述建议(1)会起作用。
定义:
#define COMMA ,
Run Code Online (Sandbox Code Playgroud)
并在必要时使用它:
FOO(baz<20 COMMA 30>);
Run Code Online (Sandbox Code Playgroud)
这不需要以任何方式修改宏定义,但如果宏将参数传递给另一个宏,则会失败。(替换将在解析内部宏调用之前完成,因此多参数问题将被推迟到内部调用。)
如果您期望一个宏参数可能包含不受保护的逗号,并且它是最后一个或唯一的参数,并且您可以修改宏,并且您使用的是 C++11/C99 或更好的(或 gcc,允许将此作为扩展一段时间),将宏变量设置为:
#define FOO(...) printf("%d\n",__VA_ARGS__::val())
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
557 次 |
| 最近记录: |