Сначала немного терминологии:
- объявление-использование :
using std::vector;
- директива использования :
using namespace std;
Я думаю, что использование директив using - это нормально, если они не используются в глобальной области в файле заголовка. Так что имея
using namespace std;
в вашем .cpp файле на самом деле не проблема, и если окажется, что это полностью под вашим контролем (и при желании его можно даже ограничить определенными блоками). Я не вижу особой причины загромождать код множеством std::
квалификаторов - это просто становится кучей визуального шума. Однако, если вы не используете std
в своем коде целую кучу имен из пространства имен, я также не вижу проблем с исключением директивы. Это тавтология - если в директиве нет необходимости, то и использовать ее не нужно.
Точно так же, если вы можете обойтись несколькими объявлениями using (вместо директив using ) для определенных типов в std
пространстве имен, тогда нет причин, по которым вы не должны иметь только эти конкретные имена, перенесенные в текущее пространство имен. К тому же, я думаю, что было бы безумием и хлопотно иметь дело с 25 или 30 объявлениями using, когда одна директива using также подойдет.
Также хорошо иметь в виду, что бывают случаи, когда вы должны использовать объявление using. Обратитесь к статье 25 Скотта Мейерса: подумайте о поддержке безбрасывающего свопа из Эффективного C ++, Третье издание. Чтобы универсальная шаблонная функция использовала «лучший» метод подкачки для параметризованного типа, вам необходимо использовать объявление с использованием объявления и поиск, зависящий от аргументов (также известный как ADL или поиск по Кенигу):
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
Я думаю, нам следует рассмотреть общие идиомы для различных языков, в которых значительно используются пространства имен. Например, Java и C # в значительной степени используют пространства имен (возможно, больше, чем C ++). Наиболее распространенный способ использования имен в пространствах имен на этих языках - их массовое внесение в текущую область действия с эквивалентом директивы using. Это не вызывает широко распространенных проблем, и в некоторых случаях проблема решается на основе «исключений», обрабатывая соответствующие имена с помощью полностью определенных имен или псевдонимов - точно так же, как это может быть сделано в C ++.
Херб Саттер и Андрей Александреску говорят об этом в «Правиле 59: Не записывайте использование пространств имен в заголовочный файл или перед #include» своей книги «Стандарты кодирования C ++: 101 правила, рекомендации и лучшие практики»:
Вкратце: вы можете и должны использовать пространство имен, используя объявления и директивы в ваших файлах реализации после #include
директив, и вам это нравится. Несмотря на неоднократные утверждения об обратном, декларации и директивы, использующие пространства имен, не являются злом и не противоречат цели пространств имен. Скорее, они делают пространства имен пригодными для использования.
Струпструп часто цитируется как сказал: «Не загрязняйте глобальное пространство имен» в «Языке программирования C ++, третье издание». Он действительно так говорит (C.14 [15]), но ссылается на главу C.10.1, где говорит:
Объявление using добавляет имя в локальную область видимости. С помощью директивы не делает; он просто делает имена доступными в той области, в которой они были объявлены. Например:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
Локально объявленное имя (объявленное обычным объявлением или использованием-объявлением) скрывает нелокальные объявления с тем же именем, а любые незаконные перегрузки имени обнаруживаются в точке объявления.
Обратите внимание на ошибку неоднозначности для k++
in
f1()
. Глобальным именам не отдается предпочтение перед именами из пространств имен, сделанных доступными в глобальной области. Это обеспечивает значительную защиту от случайных конфликтов имен и, что немаловажно, гарантирует отсутствие каких-либо преимуществ от загрязнения глобального пространства имен.
Когда библиотеки, объявляющие много имен, становятся доступными с помощью директив using, существенным преимуществом является то, что конфликты неиспользуемых имен не считаются ошибками.
...
Я надеюсь увидеть радикальное сокращение использования глобальных имен в новых программах, использующих пространства имен, по сравнению с традиционными программами на C и C ++. Правила для пространств имен были специально созданы, чтобы не давать преимуществ «ленивому» пользователю глобальных имен перед тем, кто заботится о том, чтобы не загрязнять глобальную область видимости.
И как получить такое же преимущество, как «ленивый пользователь глобальных имен»? Используя преимущество директивы using, которая безопасно делает имена в пространстве имен доступными для текущей области.
Обратите внимание, что есть различие - имена в std
пространстве имен становятся доступными для области с правильным использованием директивы using (путем размещения директивы после #includes
) не загрязняют глобальное пространство имен. Это просто делает эти имена доступными и с постоянной защитой от столкновений.