«Одной из причин была лень».
Это звонит колокола. Единственная причина, по которой вы должны сделать что-то подобное, - это то, что вы знаете, как это сделать «правильно», но вы пришли к выводу, что есть осязаемая причина не делать этого таким образом.
сказал: если данные, которые вы предпочитаете хранить таким образом, - это данные, которые вам никогда не потребуется запрашивать, тогда может быть случай для его хранения в том виде, в котором вы выбрали.
(Некоторые пользователи будет оспаривать заявление в моем предыдущем абзаце, в котором говорится, что «вы никогда не сможете узнать, какие требования будут добавлены в будущем». Эти пользователи либо ошибочны, либо заявляют о религиозной убежденности. Иногда бывает полезно работать с требованиями, которые у вас есть перед вами .)
Да, он плохо сформирован. Вот почему:
Функция constexpr
должна быть определена (не просто объявлена) перед использованием в постоянном выражении.
Итак, например:
constexpr int f(); // declare f
constexpr int x = f(); // use f - ILLEGAL, f not defined
constexpr int f() { return 5; } // define f, too late
Определения функций внутри спецификатора класса (а также инициализаторы и параметры по умолчанию) по существу разбираются в порядке, таком как они были определены вне класса.
Итак, это:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
Анализируется в следующем порядке:
struct X {
constexpr inline static int size(); // function body defered
static const int array[size()]; // <--- POINT A
};
constexpr inline int X::size() { return 5; }
То есть разбор тел функций откладывается до тех пор, пока не будет указан спецификатор класса.
Цель этой отсрочки разбора тела функции так что тела функций могут перенаправлять ссылочные классы, еще не объявленные в этой точке, а также поэтому они могут использовать свой собственный класс как полный тип:
struct X
{
void f() { T t; /* OK */ }
typedef int T;
};
По сравнению с областью пространства имен:
void f() { T t; /* error, T not declared */ }
typedef int T;
На POINT A
компилятор еще не имеет определения size()
, поэтому он не может его вызвать. Для производительности компиляции constexpr
функции должны быть определены перед их использованием в блоке трансляции перед вызовом во время компиляции, иначе компилятор должен будет сделать несколько проходов только для «ссылки» постоянных выражений для оценки.
По-видимому, это даже не ошибка , потому что его статус RESOLVED INVALID
, что означает, что люди, стоящие за GCC, и эта bugzilla, после рассмотрения проблемы, не думают, что это GCC bug.
Я напоминаю вам эту страницу, потому что есть ответ на это поведение в одном из связанных сообщений.
constexpr
в постоянном выражении, она должна быть определена (не просто объявлена) выше ее использования в блоке перевода.
– Andrew Tomazos
11 May 2013 в 06:01
constexpr
может использоваться, когда статический член данных constexpr
может.
– Ben Voigt
11 May 2013 в 06:41
static
. Если он определен как упомянутый в моем коде, тогда разрешите его использовать, иначе укажите ошибку. – iammilind 11 May 2013 в 13:23