Почему внутри неименованных пространств имен?
Быстрый для гуру: С++ 11 разрешает объявлять имена имен имен inline
. Это кажется излишним для меня; вещи, объявленные в неназванном пространстве имен, уже используются так, как если бы они были объявлены в охватывающем пространстве имен.
Итак, мой вопрос: что значит сказать
inline namespace /*anonymous*/ {
// stuff
}
и как он отличается от традиционного
namespace /*anonymous*/ {
// stuff
}
что мы знаем и любим С++ 98? Может ли кто-нибудь привести пример другого поведения, когда используется inline
?
РЕДАКТИРОВАТЬ: Просто пояснить, так как этот вопрос был отмечен как дубликат: я не спрашиваю об именах inline namespaces вообще. Я понимаю прецедент, и я думаю, что они здорово. Я специально спрашиваю, что значит объявлять неназванное пространство имен как inline
. Поскольку неназванные пространства имен обязательно всегда являются локальными для TU, рациональное управление версиями символов, похоже, не применяется, поэтому мне интересно, что делает добавление inline
.
В стороне, стандарт [7.3.1.1], касающийся неназванных пространств имен, говорит:
inline
появляется в том и только в том случае, если он отображается в определении имен без имени
но это кажется тавтологией для моих неязычных глаз адвокатов - "оно появляется в определении, если оно появляется в определении"! Что касается бонусных очков, может ли кто-нибудь объяснить, что на самом деле говорит этот бит стандартного?
РЕДАКТИРОВАТЬ: Кубби заявил о бонусной точке в комментариях:
стандарт говорит о том, что определение имени-имени-имен ведет себя так, как если бы оно было заменено на X, где inline
появляется в X, если оно появляется в пространстве имен без имени -определение
Ответы
Ответ 1
Вот одно использование, которое я нашел:
namespace widgets { inline namespace {
void foo();
} } // namespaces
void widgets::foo()
{
}
В этом примере foo
имеет внутреннюю связь, и мы можем позже определить функцию, используя синтаксис namespace::function
, чтобы убедиться, что подпись функции верна. Если бы вы не использовали пространство имен widgets
, тогда определение void foo()
определяло бы совершенно другую функцию. Вам также не нужно повторно открывать пространство имен, сохраняя уровень отступов.
Если в виджетах namespace
уже есть еще одна функция, называемая foo
, то это скорее приведет к двусмысленности, а не к неприятному нарушению ODR.
Ответ 2
Я не знаю, было ли это сделано, чтобы ответить на ваш собственный вопрос на SO, но после того, как некоторые игры вокруг моего любопытства были удовлетворены, я также могу поделиться им.
Определение встроенного пространства имен включает в себя не только подъем имен в охватываемое пространство имен (что происходит в любом случае для неназванных пространств имен), но также позволяет настраивать шаблоны, определенные внутри встроенного пространства имен, вне его. Оказывается, это относится и к неназванным пространствам имен:
inline // comment this out to change behaviour
namespace {
template <typename T> struct A {};
}
template <> struct A<int> {};
Без inline
g++ жалуется на попытку специализации шаблона из другого пространства имен (хотя Clang этого не делает). С inline
он компилируется просто отлично. С обоими компиляторами все, что определено в специализации, по-прежнему отмечено как имеющее внутреннюю связь (согласно nm
), как если бы оно находилось в неназванном пространстве имен, но я предполагаю, что это следует ожидать. Я не могу думать о какой-либо причине, почему это было бы полезно, но мы идем.
Вероятно, более полезный эффект исходит из изменения в отношении зависимого от аргументов поиска для встроенных пространств имен, что также влияет на неназванные внутренние пространства имен. Рассмотрим следующий случай:
namespace NS {
// Pretend this is defined in some header file
template <typename T>
void func(const T&) {}
// Some type definition private to this TU
inline namespace {
struct A {};
}
} // end namespace NS
int main()
{
NS::A a;
func(a);
}
Без inline
ADL терпит неудачу, и мы должны явно написать NS::func(a)
. Конечно, если бы мы определили неназванное пространство имен на уровне верхнего уровня (как обычно было бы), то мы бы не получили ADL, был ли он встроенным или нет, но все же...