我发现有点难以理解为什么以下结果会导致编译时计算。我已经阅读了this,this,this以及关于stackoverflow的更多问题,告诉我下面的代码(至少对我的理解)不应该在编译时因为while循环而计算(代码只是一个例子来说明题):
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循环?
在C ++ 14中,放松了constexpr
函数的要求。
以前,在C ++ 11中,constexpr函数只能包含typedef
s,static_assert
s和using
s,但只能包含一个return语句。
在C ++ 14中,可以在constexpr
函数体中使用循环。
因为b
被声明为constexpr char
,所以必须在编译时进行评估。编译器然后优化了isStringNice
函数,因为它在运行时没有使用。