Константы массива времени компиляции
Кажется, у меня что-то довольно фундаментальное.
Я пытаюсь использовать члены массива const во время компиляции.
const int list[3] = { 2, 5, 7 };
const int a = list[2]; // this doesn't error?
template<int N1, int N2>
struct tmax {
enum { value = ((N1 > N2) ? N1 : N2) };
};
const int b = tmax<2,4>::value;
const int c = tmax<list[0],list[1]>::value; // error is here
int main()
{
return 0;
}
Ошибки:
prog.cpp:10:24: error: 'list' cannot appear in a constant-expression
prog.cpp:10:30: error: an array reference cannot appear in a constant-expression
Ниже приведена ссылка ссылка для ссылки IDEOne
Так почему же это не работает? Что мне не хватает? Что мне делать по-другому?
Ответы
Ответ 1
Просто потому, что объект const
не означает, что это выражение постоянной времени компиляции.
main.cpp:10:20: error: non-type template argument is not a constant expression
const int c = tmax<list[0],list[1]>::value; // error is here
^~~~~~~
main.cpp:10:20: note: read of non-constexpr variable 'list' is not allowed in a constant expression
main.cpp:1:11: note: declared here
const int list[3] = { 2, 5, 7 };
^
Это причина constexpr
:
constexpr int list[3] = { 2, 5, 7 };
template<int N1, int N2>
struct tmax {
enum { value = ((N1 > N2) ? N1 : N2) };
};
const int b = tmax<2,4>::value;
const int c = tmax<list[0],list[1]>::value; // works fine now
Как это работает:
const int a = list[2]; // this doesn't error?
инициализация переменной const
не требует постоянного выражения:
int foo(int n) {
const int a = n; // initializing const var with a non-compile time constant
Ответ 2
Выражения не являются постоянными выражениями, если они содержат какое-либо из числа запрещенных подвыражений. Одним из таких запрещенных подвыражений является:
- преобразование lvalue-to-rvalue (4.1), если оно не применяется к
- значение целого или перечисляемого типа, которое относится к энергонезависимому объекту const с предшествующим инициализация, инициализация с помощью постоянного выражения или
- glvalue типа literal, который ссылается на энергонезависимый объект, определенный с помощью
constexpr
, или который ссылается к под-объекту такого объекта, или - glvalue типа literal, который относится к энергонезависимому временному объекту, чье время жизни не завершено, инициализировано постоянным выражением;
В частности, хотя имя const-объекта перечисляемого или межгорного типа, инициализированного константным инициализатором, формирует константное выражение (чтение его значения - это то, что вызывает преобразование lvalue-to-rvalue), под-объекты const-агрегата объект (например, list
в вашем примере, массив) нет, но если объявлено constexpr
.
const int list[3] = { 2, 5, 7 };
const int a = list[2];
Это допустимо, но a
не является константным выражением, поскольку оно не инициализируется постоянным выражением.
Изменив объявление list
(нам не нужно изменять объявление a
), мы можем сделать выражение a
постоянным.
constexpr int list[3] = { 2, 5, 7 };
const int a = list[2];
Поскольку list[2]
теперь является константным выражением, a
теперь является объектом const
объекта межстранового типа, инициализированного константным выражением, поэтому a
теперь может использоваться как константное выражение.