Определение вложенного пространства имен, когда включающее пространство имен является встроенным
Рассмотрим следующую демонстрационную программу
#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
но это просто по-своему странно).