Ошибка компиляции: используйте 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
функция. В твоей игрушке пример прост, в реальной жизни будет кошмар.