两款C++编译器对count_args函数是否为constexpr存在分歧
constexpr参数计数函数的编译器合法性问题
先看这段用于统计传入参数数量的代码:
#include <iostream> constexpr static int count_args() { return 0; } template<typename... SS> constexpr static int count_args(int &v, SS & ... restargs) { constexpr int rest = count_args(restargs...); return rest + 1; } int main(int argc, char **argv) { int a,b; constexpr int count = count_args(a,b); std::cerr << "count: " << count << std::endl; // 预期输出'count: 2' }
两款GCC版本的编译结果不同:
- G++ 9.4.0可以正常编译运行,输出预期的
count: 2 - G++ 10.3.0编译时报错:
> g++ -std=c++17 -o cx2.exe cx2.cpp cx2.cpp: In instantiation of 'constexpr int count_args(int&, SS& ...) [with SS = {int}]': cx2.cpp:15:16: error: 'restargs#0' is not a constant expression 15 | constexpr int rest = count_args(restargs...);
结论
G++ 10.3.0的处理是正确的,这段代码不是合法的constexpr代码。
原因解释
C++标准规定,constexpr变量的初始化表达式必须是常量表达式。问题出在constexpr int rest = count_args(restargs...);这一行:
restargs是函数参数的引用,指向的是main函数里的自动变量a、b,这些变量的地址在编译期无法确定,不属于常量表达式范畴。- 调用
count_args(a,b)时会逐层实例化模板函数,到第二层调用count_args(b)时,用这个指向自动变量的引用去初始化constexpr变量rest,违反了常量表达式的要求。
G++ 9.4.0属于旧版本编译器,对constexpr的检查不够严格,没捕捉到标准违规;而G10.3.0严格遵循C17标准规则,所以报错是符合规范的。
修正方案
去掉函数内部的constexpr变量定义,直接返回递归调用结果加1即可,编译期可直接推导参数数量,无需依赖常量表达式的引用:
#include <iostream> constexpr static int count_args() { return 0; } template<typename... SS> constexpr static int count_args(int &v, SS & ... restargs) { return count_args(restargs...) + 1; } int main(int argc, char **argv) { int a,b; constexpr int count = count_args(a,b); std::cerr << "count: " << count << std::endl; }
内容的提问来源于stack exchange,提问作者jyelon
相关产品推荐
相关产品推荐

