Оба являются постоянными времени компиляции. Но вы можете сделать const_cast первого и написать в него. Но он будет оптимизирован любым компилятором, так как это не влияет на «чтение», как это происходит во время компиляции.
Бонита Монтеро
Ответы:
347
Я считаю, что есть разница. Давайте переименуем их, чтобы нам было легче говорить о них:
Оба PI1и PI2являются постоянными, то есть вы не можете изменить их. Однако это толькоPI2 константа времени компиляции. Он должен быть инициализирован во время компиляции. PI1может быть инициализирован во время компиляции или во время выполнения. Кроме того, толькоPI2 может быть использован в контексте , который требует постоянного времени компиляции. Например:
Что вы должны использовать? Используйте то, что соответствует вашим потребностям. Вы хотите убедиться, что у вас есть постоянная времени компиляции, которую можно использовать в тех случаях, когда требуется постоянная времени компиляции? Хотите ли вы иметь возможность инициализировать его вычислениями, выполненными во время выполнения? И т.п.
Ты уверен? Потому что const int N = 10; char a[N];работает, а границы массивов должны быть константами времени компиляции.
fredoverflow
10
Я уверен, что примеры, которые я написал, проверены (протестировали каждый из них перед публикацией). Однако мой компилятор позволяет мне преобразовывать PI1в интегральную константу времени компиляции для использования в массиве, но не для использования в качестве нетипичного параметра интегрального шаблона. Так что конвертируемость во время компиляции PI1в интегральный тип кажется мне немного хитом.
Говард Хиннант
34
@FredOverflow: Индексы неконстантных массивов «работали» около десяти лет (например, для этого есть расширение g ++), но это не означает, что это строго законный C ++ (хотя некоторые более поздние стандарты C или C ++ сделали его легальным , я забыл какой) Что касается различий в константах времени компиляции, параметры шаблона и использование в качестве enumинициализатора являются единственными заметными отличиями между constи constexpr(и ни один из них не работает в doubleлюбом случае).
Деймон
17
Параграф 4 из 5.19 Выражения констант [expr.const] также являются (ненормативным) примечанием, в котором, как известно, указывается, что реализация может выполнять арифметику с плавающей запятой иначе (например, в отношении точности) во время компиляции, чем во время выполнения. Так что 1 / PI1и 1 / PI2может дать разные результаты. Я не думаю, что эта техническая специфика столь же важна, как совет в этом ответе.
Люк Дантон
4
Но это constexpr double PI3 = PI1;работает правильно для меня. (MSVS2013 ОСАГО). Что я делаю не так?
NuPagadi
77
Здесь нет разницы, но это важно, когда у вас есть тип, у которого есть конструктор.
struct S {constexpr S(int);};const S s0(0);constexpr S s1(1);
s0является константой, но она не обещает быть инициализированной во время компиляции. s1помечен constexpr, так что это константа и, поскольку Sконструктор также помечен constexpr, он будет инициализирован во время компиляции.
В основном это имеет значение, когда инициализация во время выполнения занимает много времени, и вы хотите перенести эту работу на компилятор, где это также занимает много времени, но не замедляет время выполнения скомпилированной программы.
Я согласен: я пришел к выводу, что constexprэто приведет к диагностике, если вычисление объекта во время компиляции будет невозможно. Что менее ясно, так это то, может ли функция, ожидающая постоянного параметра, выполняться во время компиляции, если параметр будет объявлен как, constа не как constexpr: т.е. будет constexpr int foo(S)ли выполняться во время компиляции, если я вызову foo(s0)?
Матье М.
4
@MatthieuM: Я сомневаюсь, foo(s0)будет ли выполняться во время компиляции, но вы никогда не знаете: компилятору разрешено делать такие оптимизации. Конечно, ни gcc 4.7.2, ни clang 3.2 не позволяют мне компилироватьconstexpr a = foo(s0);
rici
50
constexpr указывает значение, которое является постоянным и известно во время компиляции. const указывает значение, которое является только постоянным; это не обязательно знать во время компиляции.
int sz;constexprauto arraySize1 = sz;// error! sz's value unknown at compilation
std::array<int, sz> data1;// error! same problemconstexprauto arraySize2 =10;// fine, 10 is a compile-time constant
std::array<int, arraySize2> data2;// fine, arraySize2 is constexpr
Обратите внимание, что const не дает такой же гарантии, как constexpr, потому что const-объекты не нужно инициализировать значениями, известными во время компиляции.
int sz;constauto arraySize = sz;// fine, arraySize is const copy of sz
std::array<int, arraySize> data;// error! arraySize's value unknown at compilation
Все объекты constexpr являются const, но не все объекты const являются constexpr.
Если вы хотите, чтобы компиляторы гарантировали, что переменная имеет значение, которое может быть использовано в контекстах, требующих констант времени компиляции, инструмент для достижения - constexpr, а не const.
Мне очень понравилось ваше объяснение .. не могли бы вы прокомментировать, где случаи, когда нам может понадобиться использовать константы времени компиляции в реальных сценариях.
Constexpr символьная константа должна быть присвоено значение, которое известно во время компиляции. Например:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constexprint c2 = n+7;// Error: we don’t know the value of c2// ...}
Для обработки случаев, когда значение «переменной» инициализируется значением, которое не известно во время компиляции, но никогда не изменяется после инициализации, C ++ предлагает вторую форму константы ( const ). Например:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constint c2 = n+7;// OK, but don’t try to change the value of c2// ...
c2 =7;// error: c2 is a const}
Такие « константные переменные» очень распространены по двум причинам:
В C ++ 98 не было constexpr, поэтому люди использовали const .
Элемент списка «Переменные», которые не являются константными выражениями (их значение неизвестно во время компиляции), но не изменяют значения после инициализации, сами по себе широко используются.
Ссылка: «Программирование: принципы и практика с использованием C ++» от Страуструпа
Ответы:
Я считаю, что есть разница. Давайте переименуем их, чтобы нам было легче говорить о них:
Оба
PI1
иPI2
являются постоянными, то есть вы не можете изменить их. Однако это толькоPI2
константа времени компиляции. Он должен быть инициализирован во время компиляции.PI1
может быть инициализирован во время компиляции или во время выполнения. Кроме того, толькоPI2
может быть использован в контексте , который требует постоянного времени компиляции. Например:но:
и:
но:
Что вы должны использовать? Используйте то, что соответствует вашим потребностям. Вы хотите убедиться, что у вас есть постоянная времени компиляции, которую можно использовать в тех случаях, когда требуется постоянная времени компиляции? Хотите ли вы иметь возможность инициализировать его вычислениями, выполненными во время выполнения? И т.п.
источник
const int N = 10; char a[N];
работает, а границы массивов должны быть константами времени компиляции.PI1
в интегральную константу времени компиляции для использования в массиве, но не для использования в качестве нетипичного параметра интегрального шаблона. Так что конвертируемость во время компиляцииPI1
в интегральный тип кажется мне немного хитом.enum
инициализатора являются единственными заметными отличиями междуconst
иconstexpr
(и ни один из них не работает вdouble
любом случае).1 / PI1
и1 / PI2
может дать разные результаты. Я не думаю, что эта техническая специфика столь же важна, как совет в этом ответе.constexpr double PI3 = PI1;
работает правильно для меня. (MSVS2013 ОСАГО). Что я делаю не так?Здесь нет разницы, но это важно, когда у вас есть тип, у которого есть конструктор.
s0
является константой, но она не обещает быть инициализированной во время компиляции.s1
помеченconstexpr
, так что это константа и, посколькуS
конструктор также помеченconstexpr
, он будет инициализирован во время компиляции.В основном это имеет значение, когда инициализация во время выполнения занимает много времени, и вы хотите перенести эту работу на компилятор, где это также занимает много времени, но не замедляет время выполнения скомпилированной программы.
источник
constexpr
это приведет к диагностике, если вычисление объекта во время компиляции будет невозможно. Что менее ясно, так это то, может ли функция, ожидающая постоянного параметра, выполняться во время компиляции, если параметр будет объявлен как,const
а не какconstexpr
: т.е. будетconstexpr int foo(S)
ли выполняться во время компиляции, если я вызовуfoo(s0)
?foo(s0)
будет ли выполняться во время компиляции, но вы никогда не знаете: компилятору разрешено делать такие оптимизации. Конечно, ни gcc 4.7.2, ни clang 3.2 не позволяют мне компилироватьconstexpr a = foo(s0);
constexpr указывает значение, которое является постоянным и известно во время компиляции.
const указывает значение, которое является только постоянным; это не обязательно знать во время компиляции.
Обратите внимание, что const не дает такой же гарантии, как constexpr, потому что const-объекты не нужно инициализировать значениями, известными во время компиляции.
Все объекты constexpr являются const, но не все объекты const являются constexpr.
Если вы хотите, чтобы компиляторы гарантировали, что переменная имеет значение, которое может быть использовано в контекстах, требующих констант времени компиляции, инструмент для достижения - constexpr, а не const.
источник
Constexpr символьная константа должна быть присвоено значение, которое известно во время компиляции. Например:
Для обработки случаев, когда значение «переменной» инициализируется значением, которое не известно во время компиляции, но никогда не изменяется после инициализации, C ++ предлагает вторую форму константы ( const ). Например:
Такие « константные переменные» очень распространены по двум причинам:
Ссылка: «Программирование: принципы и практика с использованием C ++» от Страуструпа
источник