Ответ 1
Внутренние пространства имен - это функция управления версиями библиотек, сродни символьной версии, но реализована исключительно на уровне С++ 11 (т.е. кросс-платформенная) вместо того, чтобы быть функции определенного бинарного исполняемого формата (т.е. для конкретной платформы).
Это механизм, с помощью которого автор библиотеки может создать вложенное пространство имен и действовать так, как если бы все его объявления находились в окружающем пространстве имен (inline namespaces могут быть вложенными, поэтому "более вложенные" имена перколяются до полного первое не-встроенное пространство имен и выглядеть так, как если бы их объявления также находились в любом из пространств имен между ними.)
В качестве примера рассмотрим реализацию STL vector
. Если бы мы имели встроенные пространства имен с начала С++, то в С++ 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
. Если ваша кодовая база была написана в pre-С++ 98 раз, и вы обнаружите, что версия С++ 98 vector
вызывает у вас проблемы при обновлении вашего компилятора, "все", которое вам нужно сделать, это найти ссылки на std::vector
в вашей кодовой базе и заменить их на std::pre_cxx_1997::vector
.
Приходите к следующему стандарту, и поставщик STL снова повторяет эту процедуру, вводя новое пространство имен для std::vector
с поддержкой emplace_back
(что требует С++ 11) и вставляет это if if __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
, я получаю либо одну, либо другую из реализаций.
И вы будете почти правы.
Рассмотрим следующий допустимый код пользователя С++ 98 (было разрешено полностью специализировать шаблоны, которые живут в пространстве имен std
в С++ 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
или с встроенным пространством имен С++ 11, но не с трюком версии, который использовал using namespace <nested>
, потому что он предоставляет детали реализации, что истинное пространство имен в который был определен vector
, не был напрямую std
.
Существуют и другие отверстия, в которых вы можете обнаружить вложенное пространство имен (см. комментарии ниже), но встроенные пространства имен объединяют их все. И это все. Очень полезно в будущем, но AFAIK Standard не предписывает имена встроенных имен для собственной стандартной библиотеки (я бы хотел, чтобы это было доказано неправильно), поэтому его можно использовать только для сторонних библиотек, а не для сам стандарт (если поставщики компилятора не согласуют схему именования).