смешивать использование constexpr и const? - PullRequest
8 голосов
/ 15 февраля 2011

Я прочитал немного о реализации стандартной библиотеки CLang, и это немного смущает меня по const и constexpr.

template<class _Tp, _Tp __v>
struct integral_constant
{
    static constexpr _Tp value = __v;
};

template<class _Tp, _Tp __v>
const _Tp integral_constant<_Tp, __v>::value;

Что меня смущает, так это то, что он использует constexpr внутри определения класса и constвне.Мой вопрос, это разрешено?И при каких условиях const и constexpr могут использоваться взаимозаменяемо?Конечно, функции constexpr не могут применяться к const, поэтому я имею в виду данные const и данные constexpr.

Я прочитал некоторые стандартные черновики и предложение в http://www.open -std.org / jtc1 / sc22/wg21/docs/papers/2007/n2235.pdf, но меня это смущает.Поэтому у меня есть еще несколько вопросов:

В N2235 четко указано, что данные const не обязательно являются константами времени компиляции, см. Следующий пример:

struct S {
    static const int size;
};
const int limit = 2 * S::size; // dynamic initialization
const int S::size = 256;

и constexprдолжен решить эту проблему, поэтому по крайней мере в этой ситуации constexpr не разрешен, как показано ниже,

struct S {
    static const int size;
};
constexpr int limit = 2 * S::size; // shall be error in my understanding
const int S::size = 256;

Однако после прочтения стандартного черновика C ++ N3225 я нигде не вижу явного заявления о том, что приведенный выше пример вызовет ошибку,В частности, начиная с 7.1.5 / 9,

Спецификатор constexpr, используемый в объявлении объекта, объявляет объект как const.Такой объект должен иметь буквальный тип и должен быть инициализирован.Если он инициализируется вызовом конструктора, конструктор должен быть конструктором constexpr, и каждый аргумент конструктора должен быть константным выражением.этот вызов должен быть постоянным выражением (5.19).В противном случае каждое полное выражение, которое появляется в его инициализаторе, должно быть константным выражением.

Следовательно, если constexpr int limit = 2 * S :: size;неверно, то S :: size не должно быть константным выражением, тогда из 5.19 (константное выражение) я нигде не вижу стандартного запрета 2 * S :: size в приведенном выше примере, чтобы не быть константным выражением.

Кто-нибудь может указать на то, что я упустил?Большое спасибо.

Ответы [ 2 ]

4 голосов
/ 15 февраля 2011

S :: size не является константным выражением в соответствии с N3225 §5.19p2:

Условное выражение является константным выражением, если оно не включает одно из следующих…

  • преобразование из lvalue в rvalue (4.1), если только оно не применяется к
    • glvalue целочисленного или перечислимого типа, который относится к энергонезависимому константному объекту с предшествующей инициализацией, инициализированному с помощью постоянного выраженияили
    • [другие условия, которые не применяются]

Обратите внимание, что вторая приведенная мною точка пули позволяет использовать встроенный элемент статических данных, которыйсам по себе инициализируется константным выражением, чтобы также быть константным выражением, но ваш S :: size неинициализирован.

(Примечание: константные выражения определяются в терминах условных выражений, потому что именно так C ++грамматика работает.)

Если вам интересно, как происходит преобразование lvalue в rvalue, см. §5p9:

Всякий раз, когда выражается glvaluen появляется как операнд оператора, который ожидает значение prvalue для этого операнда, для преобразования применяются стандартные преобразования преобразования lvalue-to-rvalue (4.1), array-to-pointer (4.2) или function-to-pointer (4.3)выражение для prvalue.

Это, вероятно, хороший пример того, как чтение стандарта не может служить хорошей ссылкой , хотя для 0x еще мало что доступно.

2 голосов
/ 15 февраля 2011

"каждое полное выражение, которое появляется в его инициализаторе, должно быть константным выражением"

S::size не является константным выражением, поэтому оно не может появляться при инициализации константного выражения.

...