我发现很难理解为什么以下结果会导致编译时间计算。 我已阅读this,this,this和 由于while循环,很多关于stackoverflow的问题告诉我以下代码(至少据我所知)不应在编译时计算(代码仅是说明问题的示例):
template< unsigned N >
constexpr unsigned isStringNice(const char (&arr)[N], unsigned pos = 0)
{
//we do not like the 'D' char :)
int currPos = 0;
while(currPos < N){
if(arr [currPos] == 'D'){
throw 1;
}
currPos ++;
}
return 1;
}
constexpr unsigned isIdxValid( unsigned idx, unsigned len){
return idx >= len? throw 1 : idx;
}
template< unsigned N >
constexpr char nth_char(const char (&arr)[N], unsigned pos){
return isStringNice(arr),isIdxValid(pos, N),arr[pos];
}
int main(){
constexpr char b = nth_char("ABC", 2);
return b;
}
这将输出以下assembly代码(不带标志)(gcc 8.2,谢谢Godbolt) 主要:
push rbp
mov rbp, rsp
mov BYTE PTR [rbp-1], 67
mov eax, 67
pop rbp
ret
并带有-O3
main:
mov eax, 67
ret
请注意,那里没有跳转,while条件下没有分支,什么也没有。我的印象是for-loops和while循环were not possible在编译时进行评估。但是,编译器(gcc 8.2)在编译时评估结果。
我唯一的想法是这种情况是由于循环展开而发生的,所以我尝试使用-fno-unroll-loops
,但这导致了相同的汇编代码。另一方面,根据我的经验,此标志更像是编译器建议,而不是保证和即使设置了标志,gcc仍可能会展开循环。
我的问题的简短版本:在编译时如何评估constexpr函数中的while循环?
答案 0 :(得分:9)
在C ++ 14中,放宽了constexpr
函数的要求。
以前,在C ++ 11中,constexpr函数只能包含typedef
,static_assert
和using
s,而只能包含一个return语句。
在C ++ 14中,可以在constexpr
函数体中使用循环。
由于b
被声明为constexpr char
,因此必须在编译时进行求值。然后,编译器优化了isStringNice
函数,因为在运行时未使用该函数。