Какова область действия объявления using в C ++?

100

Я использую объявление using в C ++, чтобы добавить std :: string и std :: vector в локальное пространство имен (чтобы не вводить ненужные символы std ::).

using std::string;
using std::vector;

class Foo { /*...*/ };

Каков объем этого объявления? Если я сделаю это в заголовке, будет ли он вставлять эти объявления using в каждый файл cpp, который включает заголовок?

Джефф Лейк
источник
18
На всякий случай это не ясно из других ответов здесь: - Не помещайте usingобъявление (или usingдирективу) в область файла во включаемый файл / заголовок! Это вызовет головную боль у пользователей шапки.
Майкл Бёрр,
На самом деле, не ставят usingдекларацию (подавно директиву ) в заголовке вообще , даже в пространстве имен! См. Объем использования объявления в пространстве имен для проблем, которые это вызывает.
Нильс фон Барт
@NilsvonBarth: Это немного упрощено. Использование usingв области класса и функции безопасно в отношении обсуждаемой проблемы.
Себастьян Мах
Вы можете быть заинтересованы , чтобы прочитать о ADL C ++ поиска функции .
Alexis Wilke

Ответы:

59

Когда вы #include заголовочный файл в C ++, он помещает все содержимое заголовочного файла в то место, которое вы включили в исходный файл. Таким образом, включение файла с usingобъявлением имеет тот же эффект, что и размещение usingобъявления в верхней части каждого файла, который включает этот файл заголовка.

Джереми Рутен
источник
51
... что вообще плохо.
Catskul
17
Но если вы поместите usingобъявление внутри, namespaceоно ограничено областью этого пространства имен, поэтому в целом это нормально (с обычными оговорками в отношении ваших конкретных потребностей и стиля).
Zero
1
... но если вы помещаете using внутри пространства имен, убедитесь, что вы не пытаетесь обойти что-то, что обычно является плохой идеей, например, вы не можете заключить методы класса, объявленные вне пространства имен Y, внутри другого пространство имен X, чтобы вы могли локально использовать пространство имен X. Вот почему мы в первую очередь использовали namespace :: resolvers. Если это такая большая проблема с набором текста, либо макрос (который может легко привести к запаху кода), либо, что еще лучше, изолируйте его в его собственном исходном файле .cpp, где вы будете использовать пространство имен только там.
osirisgothra
1
Хотя этот и аналогичные ответы являются хорошими советами, они не отвечают на вопрос.
Эмиль Кормье
116

В файлах заголовков нет ничего особенного, что могло бы скрыть usingобъявление. Это простая подстановка текста еще до начала компиляции.

Вы можете ограничить usingобъявление областью:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Затмение
источник
12
Никогда не думал, что смогу использовать его внутри функции!
Агостино,
1
У меня есть куча пространств имен, которые все используются одним файлом типа «конгломератор», и модульное тестирование gmock было очень утомительным, потому что каждый тест использовал вещи из определенного пространства имен, и я думал, что должен квалифицировать каждую переменную. Использование usingвнутри функции (или даже TESTмакроса gtest !) Делает мою жизнь намного лучше!
dwanderson
54

Объем оператора using зависит от того, где он находится в коде:

  • Размещенный в верхней части файла, он имеет область действия по всему файлу.
  • Если это файл заголовка, он будет иметь область видимости во всех файлах, содержащих этот заголовок. В общем, это « плохая идея », так как это может иметь неожиданные побочные эффекты.
  • В противном случае оператор using имеет область видимости в блоке, который содержит его, от точки, в которой он встречается, до конца блока. Если он помещен в метод, он будет иметь область видимости внутри этого метода. Если он помещен в определение класса, он будет иметь область видимости внутри этого класса.
дагорым
источник
5
Я думал, что невозможно добавить usingоператор в рамках класса ...? Из-за этого у меня был тот же вопрос, что и у OP, так как я не хотел печатать std::повсюду. У меня есть классы, которые используют много векторов с умными указателями, а пятисимвольный std::префикс добавляет большую длину строки, что, как мне кажется, читается хуже. Поэтому мне было интересно, в порядке ли usingдиректива в пространстве имен, содержащем класс? (Даже если в заголовке.)
thomthom
5
А как насчет того, чтобы он попал в сферу действия namespace { ... }?
einpoklum
Таким образом, вы можете полностью написать: {using namespace blabla; class blah {}; } и что использование будет применяться только к классу?
Динаиз 01
8

Область видимости - это та область, в которой находится объявление using.

Если это глобальная область видимости, то она будет глобальной. Если он находится в глобальной области действия файла заголовка, то он будет в глобальной области действия каждого исходного файла, который включает заголовок.

Итак, общий совет - избегать использования объявлений в глобальной области заголовочных файлов .

JohnMcG
источник
3
Этого недостаточно. Замени избегайте на Don't
Мартин Йорк
1
НО лучше избегать. «Избегайте попадания в другие машины»
бобобобо
6

В указанном случае - файл («единица перевода»), что означает «да», каждый файл, который ее включает.

Вы также можете поместить оператор using внутри класса, и в этом случае он действует только для этого класса.

Как правило, если вам нужно указать пространство имен в заголовке, часто лучше просто полностью указать каждый необходимый идентификатор.

Джеймс Карран
источник
Обратите внимание, что usingобъявление в классе не ведет себя так же, как за пределами класса - например, вы не можете использовать его для переноса coutвместо std::coutв область действия класса.
Zero
2

Это верно. Область видимости - это модуль, который использует usingобъявление. Если какие-либо файлы заголовков, которые включает модуль, имеют usingобъявления, областью этих объявлений будет этот модуль, а также любые другие модули, которые включают те же заголовки.

Атес Горал
источник
1

Есть несколько довольно некорректных комментариев, когда они говорят «Не делайте этого». Это слишком сурово, но нужно понимать, когда это нормально.

Писать using std::stringникогда не бывает нормально. Запись using ImplementationDetail::Fooв свой собственный заголовок, когда этот заголовок объявляет ImplementationDetail :: Foo, может быть в порядке, тем более, если объявление using происходит в вашем пространстве имен. Например

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}
MSalters
источник
1
Затем пользователь заголовка может писатьMyNS::Foo
Питер Реммерс
Лучшим примером является using boost::posix_time::ptime. Конечно, пользователь мог писать, MyNS::ptimeно это еще не конец света, и это может быть компенсировано удобством наличия таких функций, как MyFunction(ptime a, ptime b).
Zero
5
Почему это using std::stringникогда не нормально? Даже в вашем собственном пространстве имен, чтобы сохранить много std::префиксов?
thomthom
@thomthom это нормально, если он заключен в область видимости, такую ​​как ваше собственное пространство имен.
jcoffland