emi*_*k_g 4 c++ templates constexpr c++17 constexpr-function
我有这样的代码:
template<typename ... Args>
constexpr size_t get_init_size(Args ... args) {
return sizeof...(Args);
}
template<typename ... Args>
constexpr auto make_generic_header(Args ... args) {
constexpr size_t header_lenght = get_init_size(args...);
return header_lenght;
}
constexpr auto create_ipv4_header() {
constexpr auto x = make_generic_header(0b01, 0b10, 0b01);
return x;
}
Run Code Online (Sandbox Code Playgroud)
我知道这是虚拟代码,但我将其隔离以查找错误。
编译器给我错误(GCC):
In instantiation of 'constexpr auto make_generic_header(Args&& ...) [with Args = {int, int, int}]':
/tmp/tmp.CaO5YHcqd8/network.h:39:43: required from here
/tmp/tmp.CaO5YHcqd8/network.h:31:22: error: 'args#0' is not a constant expression
31 | constexpr size_t header_lenght = get_init_size(args...);
| ^~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
我尝试将限定符const添加到函数参数,但它同样不起作用。理论上所有这些函数都可以在编译时计算。但以我的知识,我找不到问题在哪里。
constexpr变量与函数的含义不同。
对于变量来说,这意味着该变量必须是编译时的。因此,需要用常量表达式进行初始化。
\n对于函数来说,constexpr意味着除了运行时之外,函数还可以使用内部相同的代码在编译时运行。因此,您在其中所做的一切都必须适用于运行时调用。
考虑到这一点,让我们研究一下make_generic_header:
template<typename ... Args>\nconstexpr auto make_generic_header(Args ... args) {\n constexpr size_t header_lenght = get_init_size(args...);\n return header_lenght;\n}\nRun Code Online (Sandbox Code Playgroud)\n这里,header_lenght是一个constexpr变量,所以必须是编译时的。因此,get_init_size(args...)也必须在编译时完成。但是,由于各种原因,参数不是常量表达式,因此这行不通。如果这确实有效,则意味着make_generic_header函数constexpr在运行时\xc2\xb9 时不可用,这不符合其在编译时和运行时都可用的要求。
修复方法相当简单:使用在这两种情况下都有效的代码:
\ntemplate<typename ... Args>\nconstexpr auto make_generic_header(Args ... args) {\n size_t header_lenght = get_init_size(args...);\n return header_lenght;\n}\nRun Code Online (Sandbox Code Playgroud)\n你发现了吗?唯一的变化是constexpr从 中删除header_lenght。如果这个函数在编译时运行,它仍然会起作用,并且整个函数调用表达式将是一个常量表达式。
\xc2\xb9“但它在任何一个都不起作用consteval!” - 确实,答案中给出的推理足以满足constexpr,但我省略了更根本的原因,因为它与此处无关。