2017-02-08 4 views
16

Я действительно смущен о концепции constexpr, так как я прочитал constexpr, оценивается во время компиляции, поэтому он полезен для оптимизации производительности по сравнению с обычным const.Что такое constexpr в C++?

constexpr int i = 0; 
constexpr int& ri = i; 

Приведенный выше код возвращает ошибку «неверный инициализации ссылки типа„ИНТ &“из выражения типа„сопзЬ Int“», почему?

Кроме того, следующий код содержит ошибку:

constexpr int i = 0; 
constexpr int* ri = &i; 

Если я заменил constexpr ключевое слово с const, все выше работали правильно.

+0

Возможный дубликат: http://stackoverflow.com/questions/13346879/const-vs-constexpr-on-variables –

+1

Вы забыли константным спецификатором 'constexpr ИНТ сопзЬ & п = я;'. 'constexpr int i = 0;' также объявлять 'i' как const ... [demo] (http://melpon.org/wandbox/permlink/2oc2VMdtymZ93ANa) –

+0

Возможный дубликат [const vs constexpr on variables] (http: //stackoverflow.com/questions/13346879/const-vs-constexpr-on-variables) – Swapnil

ответ

6

Re

if I replaced the constexpr word with const all above worked correctly."

const int* по существу означает (const int)*, за исключением того, что вы не можете использовать круглые скобки. A constexpr int* означает constepxr (int*) (с тегом).

Это потому, что constexpr не является типом, вы не можете назвать тип constexpr int, скажем, в то время как const является частью этого типа.

Вместо

constexpr int i = 0; 
constexpr int& ri = i; 

, которая пытается объявить constexpr ссылку непредставленных const, просто написать

constexpr int i = 0; 
constexpr int const& ri = i; 

Вы можете прочитать, что в обратном направлении, как ri является ссылка на constint, который constexpr (оценивается во время компиляции).


Добавление:

Это ¹appears, что C++ 14 требует от местных Непро- staticconstexpr объекты имеют автоматическую продолжительность хранения, по модулю как если бы правила для оптимизации.

Для удовлетворения этого, то есть, чтобы сделать код переносимым для компиляторов, если вышеуказанные заявления появляются локально в функции, добавьте static, чтобы обеспечить статическую продолжительность хранения для объекта, один относится к:

void oops() 
{ 
    static constexpr int i = 0;  // Necessary with some compilers. 
    constexpr int const& ri = i; 
} 

В противном случае он не может компилироваться, например g ++, и это , вероятно,, что требуют стандарты C++ 14 и C++ 11, путем исключения подходящих ограничений на constexpr.

Примечания:
¹ ВИДЕТЬ discussion of R. Sahu's answer.

3

Как вы сказали, constexpr оценивается по адресу Время компиляции. Поэтому при компиляции значение должно оцениваться.

Например:

constexpr int i = 0; 
constexpr int& ri = i; 

Для первой линии, 0 анализу при компиляции, его значение равно 0.

Но для второй линии, компилятор должен адрес i, чтобы выполнить задание, которое определяется во время выполнения. Так что эта строка не удастся.

+0

Является ли constexpr используется только для оптимизации производительности по сравнению с константой? –

+1

@BassamNajeeb Его можно использовать для замены макросов и жестко закодированных литералов. Например, вы можете переносить макросы и литералы в функции 'constexpr' и предоставлять им значимое имя. –

1

Вот мои 2 цента:

Функция constexpr определяет вычисление, которое происходит во время компиляции. Резонный вопрос:

  • Имеет ли смысл, чтобы позволить любое вычисление?

Разумный ответ:

  • Нет, потому что для этого потребуется много техники, ресурсов и т.д. прямо внутри компилятора, пока нет прямой необходимости.

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

13
constexpr int i = 0; 
constexpr int * ri = &i; 

Вторая строка является проблемой, потому что указатель не указывает на const объекта. Сам указатель const.

Использование

constexpr int i = 0; 
constexpr int const * ri = &i; 

решает эту проблему. Однако это будет проблемой, если переменные определены в области функций.

constexpr int i = 0; 
constexpr int const* ri = &i; 

int main() {} 

является действующей программой.

void foo() 
{ 
    constexpr int i = 0; 
    constexpr int const* ri = &i; 
} 

int main() {} 

не является действительной программой.

Вот что стандарт C++ 11 должен сказать о адрес константа:

5.19 Constant expressions

3 .. An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type std::nullptr_t .

+0

Я не знаком с проблемой области функции. Я вижу, что g ++ ведет себя так, как вы заявляете, но MSVC принимает этот якобы неверный код. g ++ говорит, что 'i' не является константой, но позволяет использовать его как размер массива (а не VLA). Это непоследовательно. g ++ принимает код с добавлением 'static'. Вы уверены, что вы не сообщаете об ошибке компилятора (ошибке), как правило, на языке? Если это правило, что это такое? –

+0

@ Cheersandhth.-Alf Я думаю, что RSahu прав, нельзя указать адрес, зависящий от времени выполнения, от указателя constexpr. Представьте себе ситуацию, когда foo называется рекурсивно. 'ri' должно иметь разное значение на каждом уровне рекурсии, но сколько уровней рекурсии есть? Это может зависеть от значения времени выполнения ... –

+0

@ W.F .: Я бы не подумал, что этот аргумент будет иметь место, потому что нет смысла указывать «i» другой адрес, определенный во время выполнения, но со значением, известным во время компиляции. Это просто идиотизм. Если в текущем определении языка есть такое правило, то это явно является дефектом в стандарте. Поэтому меня интересует, что такое (предполагаемое) правило. –