Стандарт С++: переменные constexpr с пространством имен имеют внутреннюю связь?

Представьте, что у нас есть заголовок foo.h, содержащий следующее:

#ifndef FOO_H_
#define FOO_H_

namespace foo {
constexpr std::string_view kSomeString = "blah";
}

#endif  // FOO_H_

Является foo::kSomeString гарантированным наличие внутренней связи в любой единицы перевода, которая включает foo.h? Это зависит от С++ 11 и С++ 17?

В черновом проекте [basic.link]/3 говорится

Имя, имеющее область пространства имен, имеет внутреннюю привязку, если это имя [...] не-встроенная переменная типа энергонезависимого типа с константой, которая не является явно объявленным extern или ранее объявлена ​​как имеющая внешнюю связь [...]

Но я не знаю, считается ли constexpr как "const-qualified". Говорит ли стандарт где-то?

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

Ответ 1

Да, constexpr в объявлении объекта означает, что объект const. См. [dcl.constexpr]/9. И да, это означает, что kSomeString в вашем примере имеет внутреннюю привязку.

Вид нарушения ODR, о котором мы говорим, здесь не является определением самого kSomeString, а другими определениями, которые пытаются его использовать. И есть проблема именно из-за внутренней связи. Рассмотрим:

void f(const std::string_view &);

inline void g() { 
    f(foo::kSomeString); 
}

Это нарушение ODR, если оно включено в несколько единиц перевода, по существу потому, что определение g в каждой единицы перевода ссылается на другой объект.

Ответ 2

Ваше использование kSomeString совершенно правильно.

Обо всем по порядку; ваш объект является const-квалифицированным, как T.C. объяснил. Кроме того, он литерального типа, потому что он имеет конструктор constexpr. Поэтому, если вы используете его в функции, определенной в заголовочном файле, в стандарте применяется следующее исключение (глава 3.2):

Может быть более одного определения встроенной функции с внешняя связь (7.1.2), шаблон нестатической функции (14.5.6), (…) в программе при условии, что каждое определение появляется в другом перевод, и при условии, что определения удовлетворяют следующим требования. Учитывая, что такой объект с именем D определен более чем в одном блок перевода, затем

  • каждое определение D должно состоять из одинаковой последовательности токенов; и
  • в каждом определении D соответствующие имена, рассматриваемые в соответствии с 3.4, должны относиться к объекту, определенному в определении D, или должен ссылаться на тот же объект после разрешения перегрузки (13.3) и после сопоставления частичной специализации шаблона (14.8.3), за исключением того, что имя может ссылаться на объект const с внутренним или без связь, если объект имеет одинаковый литеральный тип во всех определениях D, и объект инициализируется с помощью постоянного выражения (5.19), и значение (но не адрес) объекта используется, и объект имеет одинаковое значение во всех определениях D;
  • (...)