Ошибка компиляции: используйте constexpr для объявления размера std::array

Я учусь constexpr и, насколько я понимаю, constexpr говорит компилятору вычислять функции во время компиляции, а не во время выполнения. Я использовал следующий код для тестирования, но столкнулся с ошибкой, которую я действительно не понимаю. Не могли бы вы объяснить, почему?

#include <iostream>
#include <array>
using namespace std;

constexpr int foo(int i)
{
    return i + 5;
}

int main()
{
    int i = 10;
    std::array<int, foo(5)> arr; // OK
    // But...
    std::array<int, foo(i)> arr1; // Error
}

Ошибка: значение 'iне может использоваться в постоянном выражении. Зачем? i объявляется заранее, почему это должно быть const?

1 ответ

для моего понимания constexpr говорит компилятору вычислять функции во время компиляции, а не во время выполнения.

Не совсем: с constexpr компилятор может (не должен) вычислять время компиляции функции. И компилятор делает это, когда это необходимо и возможно.

В случае

std::array<int, foo(5)> arr; // OK

это необходимо (потому что второй аргумент шаблона std::array должно быть известно во время компиляции) и возможно (потому что 5 известно во время компиляции).

Но с

int i = 10;
std::array<int, foo(i)> arr1; // Error

необходимо (std::array) но не возможно (потому что i является непостоянной переменной, и компилятор не может использовать i значение времени компиляции, но только время выполнения).

Это необходимо, но не возможно, поэтому ошибка.

Но вы можете написать

int i { 10 };
int j { foo(i) };

потому что это не возможно позвонить foo(i) время компиляции, но это не обязательно (потому что j можно инициализировать время выполнения). Так foo(i) называется (предположительно) время выполнения.

Для компиляции std::array с помощью foo(i), вы должны определить i как constexpr (или же const)

constexpr int i { 10 };

поэтому компилятор может использовать значение i время компиляции.

Зачем? я объявлен заранее, почему это должно быть const?

Короткий ответ: потому что так говорит стандарт C++11.

Длинный ответ: потому что таким образом проще создать компилятор. Если вы хотите использовать значение времени компиляции, вы можете объявить его как constexpr и компилятор проверяет, что он никогда не изменяется. Это (относительно) просто сделать.

В противном случае, если вы можете использовать время компиляции значение неконстантной переменной, компилятор должен следовать истории переменной, чтобы определить ее значение при использовании в constexpr функция. В твоей игрушке пример прост, в реальной жизни будет кошмар.

Другие вопросы по тегам