Using-директивы использовать очень просто: стоит написать одну такую директиву, и все члены пространства имен сразу становятся видимыми. Однако чрезмерное увлечение ими возвращает нас к старой проблеме засорения глобального пространства имен:
namespace cplusplus_primer {
class matrix { };
// прочие вещи ...
}
namespace DisneyFeatureAnimation {
class matrix { };
// здесь тоже ...
using namespace cplusplus_primer;
using namespace DisneyFeatureAnimation;
matrix m; //ошибка, неоднозначность:
// cplusplus_primer::matrix или DisneyFeatureAnimation::matrix?
Ошибки неоднозначности, вызываемые using-директивой, обнаруживаются только в момент использования. В данном случае – при употреблении имени matrix. Такая ошибка, найденная не сразу, может стать сюрпризом: заголовочные файлы не менялись и никаких новых объявлений в программу добавлено не было. Ошибка появилась после того, как мы решили воспользоваться новыми средствами из библиотеки.
Using-директивы очень полезны при переводе приложений на новые версии библиотек, использующие пространства имен. Однако употребление большого числа using-директив возвращает нас к проблеме засорения глобального пространства имен. Эту проблему можно свести к минимуму, если заменить using-директивы более селективными using-объявлениями. Ошибки неоднозначности, вызываемые ими, обнаруживаются в момент объявления. Мы рекомендуем пользоваться using-объявлениями, а не using-директивами, чтобы избежать засорения глобального пространства имен в своей программе.
8.6.4. Стандартное пространство имен std
Все компоненты стандартной библиотеки С++ находятся в пространстве имен std. Каждая функция, объект и шаблон класса, объявленные в стандартном заголовочном файле, таком, как vector или iostream, принадлежат к этому пространству.
Если все компоненты библиотеки объявлены в std, то какая ошибка допущена в данном примере:
#include vector
#include string
#include iterator
int main()
{
// привязка istream_iterator к стандартному вводу
istream_iteratorstring infile( cin );
// istream_iterator, отмечающий end-of-stream
istream_iteratorstring eos;
// инициализация svec элементами, считываемыми из cin
vectorstring svec( infile, eos );
// ...
}
Правильно, этот фрагмент кода не компилируется, потому что члены пространства имен std должны использоваться с указанием их специфицированных имен. Для того чтобы исправить положение, мы можем выбрать один из следующих способов:
* заменить имена членов пространства std в этом примере соответствующими специфицированными именами;
* применить using-объявления, чтобы сделать видимыми используемые члены пространства std;
* употребить using-директиву, сделав видимыми все члены пространства std.
Членами пространства имен std в этом примере являются: шаблон класса istream_iterator, стандартный входной поток cin, класс string и шаблон класса vector.
Простейшее решение – добавить using-директиву после директивы препроцессора #include:
using namespace std;
В данном примере using-директива делает все члены пространства std видимыми. Однако не все они нам нужны. Предпочтительнее пользоваться using-объявлениями, чтобы уменьшить вероятность коллизии имен при последующем добавлении в программу глобальных объявлений.
Using-объявления, необходимые для компиляции этого примера, таковы:
using std::istream_iterator;
using std::string;
using std::cin;
using std::vector;
Но куда их поместить? Если программа состоит из большого количества файлов, можно для удобства создать заголовочный файл, содержащий все эти using-объявления, и включать его в исходные файлы вслед за заголовочными файлами стандартной библиотеки.
В нашей книге мы не употребляли using-объявлений. Это сделано, во-первых, для того, чтобы сократить размер кода, а во-вторых, потому, что большинство примеров компилировались в реализации С++, не поддерживающей пространства имен. Подразумевается, что using-объявления указаны для всех членов пространства имен std, используемых в примерах.
Поясните разницу между using-объявлениями и using-директивами.
Напишите все необходимые using-объявления для примера из раздела 6.14.
Возьмем следующий фрагмент кода:
namespace Exercise {
int ivar = 0;