c++预处理器不知道模板参数
C++ preprocessors are not aware of template arguments?
看起来,如果将多个参数传递给宏作为参数的模板实例化,c++预处理器将失败。
请看下面的例子。
#include <stdio.h>
#define FOO(v) printf("%dn",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("%dn",bar<1>::val());
printf("%dn",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
}
用clang++和g++测试
它应该被认为是一个bug吗?
不,这不是bug。
c预处理器与语言的其他部分不同,它有自己的规则。改变这个会在很大程度上破坏兼容性,CPP是高度严格标准化的。
通常解决这些逗号问题的方法是,
typedef baz<20,30> baz2030_type;
FOO(baz2030_type);
C/c++预处理器将逗号识别为宏参数分隔符,除非它们嵌套在括号内。括号。括号、大括号和模板标记不算数:
列表中的单个参数由逗号预处理标记分隔,但是匹配的内括号之间的逗号预处理标记不会分隔参数。(c++ 14教派;16.3/11;C11教派;6.10.3/11)
(上面的一个副作用是可以使用不平衡的大括号和大括号作为宏参数。这通常不是一个很好的主意,但如果你有必要,你可以这样做。
结果偶尔会出现问题;一个常见的问题是当参数应该是一个代码块时,不需要多个参数:
MY_FANCY_MACRO(1000, { int i=0, j=42; ... })
在这里,宏被调用(至少)3个参数,尽管它可能被编写为接受2个参数。
使用现代c++(和C)编译器,您有几个选项。以相当主观的顺序:
将宏重写为内联函数。如果参数是一个代码块,请考虑使用可以接受lambda或其他函子的模板化函数。如果参数是类型,则将其改为模板参数。
如果用多余的圆括号括住参数在语法上是合法的,那么就这样做。但在这种情况下,几乎可以肯定,上述建议(1)是有效的。
定义:
#define COMMA ,
并在必要时使用:
FOO(baz<20 COMMA 30>);
不需要以任何方式修改宏定义,但如果宏将参数传递给另一个宏,则会失败。(替换将在解析内部宏调用之前完成,因此多参数问题将被推迟到内部调用。)
如果您期望一个宏参数可能包含未受保护的逗号,并且它是最后一个或唯一的参数,并且您可以修改宏,并且您正在使用c++ 11/C99或更好的版本(或gcc,它已经允许将其作为一段时间的扩展),请将宏设置为可变的:
#define FOO(...) printf("%dn",__VA_ARGS__::val())
宏的参数被视为纯文本字符串,参数之间使用逗号分隔。因此,模板中的逗号将被视为分隔符。因此,预处理器将认为您向单个参数宏传递了两个参数,从而产生错误。
BOOST_IDENTITY_TYPE是解决方案:https://www.boost.org/doc/libs/1_73_0/libs/utility/identity_type/doc/html/index.html
您也可以将类型包装到decltype: decltype(std::pair<int, int>()) var;
中,这也会添加一个额外的括号,但不幸的是,这需要额外的tor调用。
- 如何在不知道C++中有多少可选参数的情况下在循环中使用va_arg?
- 没有函数模板的实例与我不知道为什么的参数列表匹配
- 创建一个带有 lambda 的 std::函数,而不知道函数的参数
- 在不知道模板参数的情况下传递模板
- 我不知道如何调用参数为节点类型的函数
- 不知道为什么我收到有关 std::size_t 不包含参数包的编译错误
- 我可以知道为什么这个函数的参数不是 int 类型吗?我不明白这里指针的整个概念
- 重载模板化 lambda,而不知道非模板化参数的参数类型
- 在不知道名称的情况下访问函数参数
- 如何使用 dlsym() 调用函数,如果我不知道返回类型和参数
- c++在不知道其参数的情况下保留对模板实例的引用
- 如何在不知道参数数量时使用模板
- 当我不知道类型时如何将参数传递给函数
- c++预处理器不知道模板参数
- 不知道参数 1 从 sf::Vector2i 到 const sf::Vector2i& 的转换<float>
- 如何将函数指针(我们不知道参数的函数)声明为类成员?
- 当您不知道传递给重写函数的参数时,在基类中创建重写方法?
- c++如何在不知道确切参数的情况下定义函数
- Numpy NDPointer:不知道如何转换参数 1
- 如果不知道特殊成员函数的参数类型,如何默认其参数类型?