TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.34K subscribers
Post #155 1.85K
Inline namespace

В этом сообщении Михаил попросил нас сделать пост про inline namespace'ы. Это хорошо вписывается в контекст постинга в последние месяцы, когда мы много говорим о линковке и inline. Поэтому держите.

Ключевое слово inline используется либо как подсказка компилятору для встраивания кода функции в место ее вызова, либо как средство обхода ODR. Применять его можно и к функциям, и к переменным(с С++17). Но есть еще одно интересное применение inline. Им мы можем пометить пространство имен. Такая пометка неймспейсов доступна с С++11. Я бы сказал, что судя по названию и уже усвоенной инфе, мы можем понять, что это значит. Но нет. Нихрена не понятно. Поэтому будем разбираться.

Контекст и использование встроенных неймспейсов совсем простой, однако он отличается от поведения других inline сущностей. Все, что объявлено внутри такого пространства имен, считается также членом внешнего неймспейса, которое содержит в себе данный inline namespace. То есть

namespace trah {
inline namespace tibidoh {
template<typename T> class tibidoh{ /* ... */ };
}
template<typename T> void tenberg(T) { /* ... */ }
}


есть у нас вот такая иерархия. Неймспейс трах. У него есть шаблонная функция тенберг. И в него вложен встроеный неймспейс тибедох. В этом внутреннем неймспейсе шаблонный класс тибедох. И прикол в том, что вместо trah::tibidoh::tibidoh я могу написать просто trah::tibidoh и использовать вложенный класс наряду с функцией trah::tenberg.

То есть в общем и целом, этот механизм позволяет автору кода сделать так, чтобы все объявления во вложенном неймспейсе выглядели и действовали, как объявления внешнего неймспейса. Более того, если есть несколько вложенных встроенных неймспейсов, то все объявления всех вложенных неймспейсов доступны в первом невстроенном пространстве имен.

Для чего это нужно? По сути эта фича призвана решить одну единственную проблему - версионирование библиотеки. Глянем на прошлый пример. Библиотека trah активно развивается и, начиная с какой-то версии, в ней появился класс tibedoh, которого не было в предыдущей версии библиотеки. До появления С++11 это выглядело бы примерно так:

namespace trah {
# if __version == new
using namespace tibidoh;
# endif
namespace tibidoh {
template<typename T> class tibidoh{ /* ... */ };
}
template<typename T> void tenberg(T) { /* ... */ }
}


В этом случае нам недоступен класс tibidoh, если мы не используем новую версию либы. А если используем, то using помогает нам не писать оператор разрешения имен и пользоваться классом tibidoh, как если бы он был членом неймспейса trah. То есть вот так trah::tibidoh. Вроде все круто и нет проблем. Но не все так просто.

Мне, как пользователю библиотеки, не желательно что-то объявлять в пространстве имен trah, по аналогии с std. Однако мне разрешается делать полную специализацию для шаблонов непосредственно в trah без последствий. Я, как автор своих классов, лучше знаю, как ими нужно оперировать, чтобы достичь максимального перфоманса. Зная API библиотеки, я думаю, что класс tibedoh объявлен в trah. Окей, пишу:

namespace trah {
template <>
class tibidoh<AbraKadabra> {
// ...
};
}


Но вот проблема. Мне позволяется полностью специализировать шаблоны именно в том пространстве имен, в котором шаблон объявлен. А на самом деле он объявлен во вложенном неймспейсе. Предыдущий код мог бы сработать для неверсионированной либы, но в нашем случае будет просто ошибка компиляции.

Это не единственный пример, когда вложенное пространство имен становится видным пользовательскому коду. Например, ADL(кто знает, тот знает, раскрытие adl не влезет в этом пост) не следует директиве using и при поиске символа из вложенного неймспейса во внешнем. ADL будет очень стараться, но так и не найдет нужный символ, который на самом деле спрятан во вложенном namespace.

Продолжение в комментах

#cpp11 #cppcore
  • 🔥 11
  • 👍 6
  • ❤ 3
  • 🤔 1
More from @grokaemcpp
  1. Oct 17, 2026Оптимистичные и пессимистичные блокировки #опытным Концепция блокировок уходит далеко за п…
  2. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  3. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  4. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  5. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  6. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →