Встроенные пространства имен - это функция управления версиями библиотеки, похожая на управление версиями символов , но реализованная исключительно на уровне C ++ 11 (т. Е. Кроссплатформенный), вместо того, чтобы быть функцией определенного двоичного исполняемого формата (т. Е. Зависящего от платформы).
Это механизм, с помощью которого автор библиотеки может выглядеть как вложенное пространство имен и действовать так, как если бы все его объявления были в окружающем пространстве имен (встроенные пространства имен могут быть вложенными, поэтому «более вложенные» имена просачиваются вплоть до первого -inline пространство имен и выглядят и действуют так, как будто их объявления были в любом из пространств имен между ними).
В качестве примера рассмотрим реализацию STL vector
. Если бы у нас были встроенные пространства имен с начала C ++, то в C ++ 98 заголовок <vector>
мог бы выглядеть так:
namespace std {
#if __cplusplus < 1997L // pre-standard C++
inline
#endif
namespace pre_cxx_1997 {
template <class T> __vector_impl; // implementation class
template <class T> // e.g. w/o allocator argument
class vector : __vector_impl<T> { // private inheritance
// ...
};
}
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
# if __cplusplus == 1997L // C++98/03
inline
# endif
namespace cxx_1997 {
// std::vector now has an allocator argument
template <class T, class Alloc=std::allocator<T> >
class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
// ...
};
// and vector<bool> is special:
template <class Alloc=std::allocator<bool> >
class vector<bool> {
// ...
};
};
#endif // C++98/03 or later
} // namespace std
В зависимости от значения __cplusplus
выбирается одна или другая vector
реализация. Если кодовый была написано в предварительно C ++ 98 раз, и вы обнаружите , что C ++ 98 версии vector
вызывают проблемы для вас , когда вы обновить ваш компилятор, «все» вы должны сделать , это найти ссылки на std::vector
в ваша кодовая база и заменить их на std::pre_cxx_1997::vector
.
Приходите к следующему стандарту, и поставщик STL просто повторяет процедуру снова, вводя новое пространство имен std::vector
с emplace_back
поддержкой (для которого требуется C ++ 11) и вставляя этот iff __cplusplus == 201103L
.
Хорошо, так зачем мне для этого нужна новая языковая функция? Я уже могу сделать следующее, чтобы иметь тот же эффект, нет?
namespace std {
namespace pre_cxx_1997 {
// ...
}
#if __cplusplus < 1997L // pre-standard C++
using namespace pre_cxx_1997;
#endif
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
namespace cxx_1997 {
// ...
};
# if __cplusplus == 1997L // C++98/03
using namespace cxx_1997;
# endif
#endif // C++98/03 or later
} // namespace std
В зависимости от значения __cplusplus
, я получаю одну или другую реализацию.
И ты был бы почти прав.
Рассмотрим следующий допустимый код пользователя C ++ 98 (было разрешено полностью специализировать шаблоны, которые уже существуют в пространстве имен std
в C ++ 98):
// I don't trust my STL vendor to do this optimisation, so force these
// specializations myself:
namespace std {
template <>
class vector<MyType> : my_special_vector<MyType> {
// ...
};
template <>
class vector<MyOtherType> : my_special_vector<MyOtherType> {
// ...
};
// ...etc...
} // namespace std
Это совершенно правильный код, где пользователь предоставляет свою собственную реализацию вектора для набора типов, где он, очевидно, знает более эффективную реализацию, чем та, что найдена в (его копии) STL.
Но : Когда вы специализируете шаблон, вы должны сделать это в пространстве имен, в котором он был объявлен. Стандарт гласит, что vector
он объявлен в пространстве имен std
, так что именно здесь пользователь по праву ожидает специализировать тип.
Этот код работает с не версионным пространством имен std
или с функцией встроенного пространства имен C ++ 11, но не с трюком версионирования, который использовался using namespace <nested>
, потому что он раскрывает детали реализации, что истинное пространство имен, в котором vector
было определено, не было std
напрямую.
Существуют и другие дыры, с помощью которых вы можете обнаружить вложенное пространство имен (см. Комментарии ниже), но встроенные пространства имен закрывают их все. И это все, что нужно сделать. Чрезвычайно полезно для будущего, но AFAIK Стандарт не предписывает встроенные имена пространств имен для своей собственной стандартной библиотеки (хотя я бы хотел, чтобы это было ошибочно), поэтому его можно использовать только для сторонних библиотек, но не для сам стандарт (если поставщики компиляторов не договорились о схеме именования).
using namespace V99;
не работает в примере Страуструпа.