Оптимизация цикла компиляции - PullRequest
4 голосов
/ 20 марта 2019

Мне трудно понять, почему следующие результаты приводят к вычислению времени компиляции. Я прочитал это , это , это и еще много вопросов о 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;
}

это выводит без флага следующую сборку код (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

Обратите внимание, что там нет прыжка, нет ветвления в состоянии "время", ничего. У меня сложилось впечатление, что for-loop и while-циклы невозможно было оценить во время компиляции. Однако компилятор (gcc 8.2) оценивает результат во время компиляции. Моя единственная мысль, что это происходит из-за циклического развертывания, поэтому я попытался использовать -fno-unroll-loops, но это приводит к тому же ассемблерному коду. С другой стороны, из моего опыта, этот флаг больше похож на предложение компилятора, чем на гарантию, и gcc может по-прежнему разверните цикл, даже если флаг установлен.

Краткая версия моего вопроса : Почему мой цикл while в функции constexpr вычисляется во время компиляции?

1 Ответ

9 голосов
/ 20 марта 2019

В C ++ 14 требования к функциям constexpr были смягчены.

Ранее в C ++ 11 функции constexpr могли содержать только typedef s, static_asserts и using s, но только один оператор возврата.

В C ++ 14 стало возможным использовать циклы в constexpr телах функций.

Поскольку b былобъявленный как constexpr char, он должен быть оценен во время компиляции.Затем компилятор оптимизировал функцию isStringNice, поскольку она не используется во время выполнения.

...