Причина, по которой 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
, как указано в настоящий момент, не будет влиять на такие переменные. И изменение существующего поведения сломало бы существующие программы.