Есть ли разница между следующими определениями?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
Если нет, какой стиль предпочтительнее в C ++ 11?
Есть ли разница между следующими определениями?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
Если нет, какой стиль предпочтительнее в C ++ 11?
Ответы:
Я считаю, что есть разница. Давайте переименуем их, чтобы нам было легче говорить о них:
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
Оба PI1
и PI2
являются постоянными, то есть вы не можете изменить их. Однако это только PI2
константа времени компиляции. Он должен быть инициализирован во время компиляции. PI1
может быть инициализирован во время компиляции или во время выполнения. Кроме того, только PI2
может быть использован в контексте , который требует постоянного времени компиляции. Например:
constexpr double PI3 = PI1; // error
но:
constexpr double PI3 = PI2; // ok
и:
static_assert(PI1 == 3.141592653589793, ""); // error
но:
static_assert(PI2 == 3.141592653589793, ""); // ok
Что вы должны использовать? Используйте то, что соответствует вашим потребностям. Вы хотите убедиться, что у вас есть постоянная времени компиляции, которую можно использовать в тех случаях, когда требуется постоянная времени компиляции? Хотите ли вы иметь возможность инициализировать его вычислениями, выполненными во время выполнения? И т.п.
const int N = 10; char a[N];
работает, а границы массивов должны быть константами времени компиляции.
PI1
в интегральную константу времени компиляции для использования в массиве, но не для использования в качестве нетипичного параметра интегрального шаблона. Так что конвертируемость во время компиляции PI1
в интегральный тип кажется мне немного хитом.
enum
инициализатора являются единственными заметными отличиями между const
и constexpr
(и ни один из них не работает в double
любом случае).
1 / PI1
и 1 / PI2
может дать разные результаты. Я не думаю, что эта техническая специфика столь же важна, как совет в этом ответе.
constexpr double PI3 = PI1;
работает правильно для меня. (MSVS2013 ОСАГО). Что я делаю не так?
Здесь нет разницы, но это важно, когда у вас есть тип, у которого есть конструктор.
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)
?
foo(s0)
будет ли выполняться во время компиляции, но вы никогда не знаете: компилятору разрешено делать такие оптимизации. Конечно, ни gcc 4.7.2, ни clang 3.2 не позволяют мне компилироватьconstexpr a = foo(s0);
constexpr указывает значение, которое является постоянным и известно во время компиляции.
const указывает значение, которое является только постоянным; это не обязательно знать во время компиляции.
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr
Обратите внимание, что const не дает такой же гарантии, как constexpr, потому что const-объекты не нужно инициализировать значениями, известными во время компиляции.
int sz;
const auto 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 символьная константа должна быть присвоено значение, которое известно во время компиляции. Например:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int c2 = n+7; // Error: we don’t know the value of c2
// ...
}
Для обработки случаев, когда значение «переменной» инициализируется значением, которое не известно во время компиляции, но никогда не изменяется после инициализации, C ++ предлагает вторую форму константы ( const ). Например:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int c2 = n+7; // OK, but don’t try to change the value of c2
// ...
c2 = 7; // error: c2 is a const
}
Такие « константные переменные» очень распространены по двум причинам:
Ссылка: «Программирование: принципы и практика с использованием C ++» от Страуструпа