Определение вложенного пространства имен, когда включающее пространство имен является встроенным

Рассмотрим следующую демонстрационную программу

#include <iostream>

inline namespace A
{
}

namespace A:: inline B
{
    void f() { std::cout << "Hello nested namespace definition.\n"; }
}

int main() 
{
    f();

    return 0;
}

Результат компиляции программы компилятором clang HEAD 11.0.0 следующее

prog.cc:7:11: warning: inline namespace reopened as a non-inline namespace
namespace A:: inline B
          ^
inline 
prog.cc:3:18: note: previous definition is here
inline namespace A
                 ^
1 warning generated.
Hello nested namespace definition.

Но согласно грамматике определения вложенного пространства имен я не могу использовать ключевое слово inline перед пространством имен A.

Так это ошибка компилятора или я что-то делаю не так?

Кстати компилятор gcc HEAD 10.0.1 20200 компилирует программу без предупреждения.

1 ответ

Решение

Подсказка fixit для clang вводит в заблуждение (поскольку вы на самом деле не можете делать то, что он вам говорит), но программа в порядке (хотя и вводит в заблуждение, поскольку похоже, что вы объявляете не встроенное пространство имен, когда вы на самом деле нет - поэтому предупреждение не совсем необоснованное).


На данный момент игнорируя вложенные пространства имен, это нормально:

inline namespace N { int i=0; };
namespace N { int j=1; };
int k=j;

Единственное правило, которое у нас есть, из [namespace.def] / 3, это (выделено мной):

В inlineКлючевое слово может использоваться в определении пространства имен, которое расширяет пространство имен, только если оно ранее использовалось в определении пространства имен, в котором изначально было объявлено имя пространства имен для этого пространства имен.

Формулировка - "только если", а не "тогда и только тогда", поэтому вы не можете пометить пространство имен. inline который ранее не был отмечен... но если первое объявление пространства имен inline, не каждое последующее объявление должно быть.

Как отмечено в OP, clang в любом случае предупреждает об этом. Потому что это вводит в заблуждение.


Но почему мы не можем просто придерживаться ведущей inline там?

Как описано в документе, проблема с разрешением вложенного пространства имен с ведущим пространством именinline в том, что это приводит к двусмысленности для программистов:

inline namespace std::experimental::parallelism_v2;  // not immediately to reader,
                                                     // is std or parallelism_v2 inline?

И то же самое было бы, если бы вы согласовали ведущие inline с вложенными inline положив его на другую сторону namespace:

namespace inline std::experimental::parallelism_v2;  // immediately to reader?
                                                     // std or parallelism_v2 inline?

Значит, это не поддерживается. Если вам нужно вложенное пространство имен с пространством имен верхнего уровняinline... ты не можешь. Пространство имен верхнего уровня не должно бытьinline (Полагаю, мы могли бы рассмотреть синтаксис вроде namespace ::inline N::inline M но это просто по-своему странно).


Другие вопросы по тегам