Killing Magic Numbers: "const int" против "constexpr int" (или нет разницы в конце) - PullRequest
11 голосов
/ 09 июля 2019

Допустим, у меня есть magic number Я хочу избавиться ...

//whatever.cpp

for (int i = 0; i < 42; i++)
{
    //...
}

Разумно, я мог убить его двумя способами:

Либо с const int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
или с constexpr int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
в исходном .cpp файле.

Есть ли какая-либо значимая разница между этими двумя в этом случае (я вспоминаю, что компилятор сделал вывод, что - в любом случае - что значение не изменяется, и, таким образом, 42 фактически жестко закодирован в получающемся цикле / развернутом цикле / что угодно машинный код) или все сводится к личному вкусу?

В связанной проблеме: что, если бы magic number (и, следовательно, то, что его заменяет) было объявлено в файле заголовка (.h) вместо файла источника (.ccp) - это изменило бы вещи ( и если да, то как)?

Ответы [ 2 ]

15 голосов
/ 09 июля 2019

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

const int i = 42; // OK, usable in a constant expression
int j = 42;
const int k = j;  // OK, not usable in a constant expression

constexpr int гарантирует, что инициализатором вашей переменной является константное выражение , иначе ваша программа не будет компилироваться.

constexpr int i = 42; // OK, usable in a constant expression
int j = 42;
constexpr int k = j;  // Compile-time error, 'j' is not a constant expression

Поэтому, если вы хотите убедиться, что ваш инициализатор действительно является константным выражением , constexpr - лучший выбор.

11 голосов
/ 09 июля 2019

Есть ли какая-либо значимая разница между этими двумя в этом случае (я вспоминаю компиляцию, выводящую, что - в любом случае - значение не изменяется и фактически жестко кодирует 42 в результирующем цикле / развернутом цикле / любом другом коде) или делает это дошли до личного вкуса?

В коде, указанном вами, не будет никакой разницы в коде.

Однако, разница в том, что переменная constexpr гарантирует, что значение известно во время компиляции. См. Ответ @ VittorioRomeo.

Также полезно написать constexpr, если это действительно значение времени компиляции, для целей документирования: когда кто-то читает ваш код и видит constexpr, они автоматически знают, что это действительно фиксированное значение. Это важно в случае, если инициализация нетривиальна (например, вызов функции).

Вы также можете видеть constexpr переменные как истинную замену макросов C, которые содержат литералы (например, #define FOO 123).

Наконец, помните, что constexpr подразумевает const.

В смежном вопросе: что, если бы магическое число (и то, что его заменяет) было объявлено в заголовочном файле вместо файла .ccp - это изменило бы вещи?

Нет. Однако, если вы объявляете глобальные переменные в заголовочном файле, вы, вероятно, захотите использовать inline (доступно в C ++ 17) поверх constexpr, чтобы в программе была только одна сущность, которая преимущество, позволяющее избежать проблем с ODR и, возможно, сэкономить память и время инициализации.

См. Должны ли переменные `const` и` constexpr` в заголовках быть `inline` для предотвращения нарушений ODR? для получения дополнительной информации.

...