Почему статические переменные constexpr, не являющиеся членами, не являются неявно встроенными? - PullRequest
0 голосов
/ 27 июня 2018

В C ++ 17 мы получили встроенные переменные, и я предположил, что глобальные переменные constexpr неявно встроены. Но, очевидно, это верно только для статических member переменных.

Какое логическое / техническое ограничение стоит за этим?

Источник:

Статическая переменная-член (но не переменная пространства имен), объявленная constexpr, неявно является встроенной переменной.

Ответы [ 2 ]

0 голосов
/ 11 июля 2018

Дело в том, что constexpr int x = 1; в области имен имеет внутреннюю связь в C ++ 14.

Если вы сделаете это неявно встроенным, не изменяя внутреннюю часть связи, изменение не будет иметь никакого эффекта, потому что внутренняя связь означает, что она не может быть определена в других единицах перевода в любом случае. И это вредит обучаемости, потому что мы хотим, чтобы такие вещи, как inline constexpr int x = 1;, получали внешнее связывание по умолчанию (в конце концов, весь смысл встроенного кода заключается в том, чтобы разрешить определение одной и той же переменной в нескольких единицах перевода).

Если вы сделаете это неявно встроенным во внешнюю связь, то вы нарушите существующий код:

// TU1
constexpr int x = 1;

// TU2
constexpr int x = 2;

Этот совершенно правильный C ++ 14 станет нарушением ODR.

0 голосов
/ 27 июня 2018

Причина, по которой constexpr члены статических данных были сделаны неявно inline, заключалась в том, чтобы решить распространенную проблему в C ++: при определении константы в области классов ранее было необходимо выдать определение ровно в одной единице перевода, чтобы переменная будет использоваться ODR:

// foo.h
struct foo {
    static constexpr int kAnswer = 42;
};

// foo.cpp
// a linker error will occur if this definition is omitted before C++17
#include "foo.h"
constexpr int foo::kAnswer;

// main.cpp
#include "foo.h"
#include <vector>
int main() {
    std::vector<int> bar;
    bar.push_back(foo::kAnswer);  // ODR-use of 42
}

В таких случаях мы обычно заботимся только о значении константы, а не об ее адресе; и компилятору удобно синтезировать уникальное местоположение для константы в случае, если она действительно используется ODR, но нам все равно, где это местоположение.

Таким образом, C ++ 17 изменил правила, так что определение вне строки больше не требуется. Для этого он делает объявление foo::kAnswer встроенным определением, чтобы оно могло появляться в нескольких единицах перевода без столкновения, как встроенные функции.

Для переменных namespace-scope constexpr (которые неявно static и, следовательно, имеют внутреннюю связь, если не объявлено extern), подобной проблемы не существует. Каждая единица перевода имеет свою копию. inline, как указано в настоящий момент, не будет влиять на такие переменные. И изменение существующего поведения сломало бы существующие программы.

...