Яка сфера застосування "використання" в C ++?


100

Я використовую декларацію 'using' в C ++, щоб додати std :: string та std :: vector до локального простору імен (щоб зберегти введення зайвих 'std ::' s).

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

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

Яка сфера дії цієї декларації? Якщо я зроблю це в заголовку, чи введе ці "використання" декларації у кожен файл cpp, що включає заголовок?


18
Про всяк випадок, коли з інших відповідей тут не зрозуміло: - Не ставте usingдекларацію (чи usingдирективу) на область дії файлу у файл, що включає файл / заголовок! Це спричинить головний біль у користувачів заголовка.
Майкл Берр

Насправді, не кладіть usingдекларацію ( директива fortiori ) взагалі в заголовок , навіть у просторі імен! Дивіться сферу використання декларації в просторі імен для проблем, які це викликає.
Нілс фон Барт

@NilsvonBarth: Це трохи спрощено. Використання usingв області та класах функцій є безпечним щодо обговорюваної проблеми.
Себастьян Мах


Можливо, вам буде цікаво почитати про функцію пошуку AD + C ++ .
Алексіс Вілке

Відповіді:


59

Коли ви #include файл заголовка в C ++, він розміщує весь вміст заголовного файлу на місці, яке ви включили до вихідного файлу. Таким чином, включення файлу, який має usingдекларацію, має такий самий ефект, як розміщення usingдекларації у верхній частині кожного файлу, що включає цей файл заголовка.


51
... що взагалі погано.
Кацкул

17
Але якщо ви помістите usingдекларацію всередині, namespaceце обмежується сферою дії цього простору імен, то це, як правило, нормально (із звичайними застереженнями щодо ваших конкретних потреб та стилю).
Нуль

1
... але якщо ви все-таки використовуєте всередині простору імен, переконайтеся, що ви цього не робите, щоб спробувати обійти щось, що зазвичай є поганою ідеєю, як, наприклад, ви не можете застосувати методи класу, оголошені поза простором імен Y всередині іншого простору імен X, так що ви можете локально використовувати простір імен X. Ось чому ми в першу чергу використовуємо простір імен :: розв’язувачі. Якщо це велика проблема введення тексту, будь то макрос (який може легко призвести до запаху коду) або ще краще, виділіть його у власне джерело .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макрос!) Робить моє життя набагато кращим!
dwanderson

54

Обсяг використовуваного оператора залежить від того, де він знаходиться в коді:

  • Розміщений у верхній частині файлу, він має область в усьому цьому файлі.
  • Якщо це файл заголовка, він буде мати область для всіх файлів, що містять це заголовок. Взагалі це " не дуже гарна ідея ", оскільки може мати несподівані побічні ефекти
  • В іншому випадку оператор, що використовує, має область дії в блоці, який містить його з моменту, коли він виникає до кінця блоку. Якщо він розміщений у межах методу, він буде мати рамки в межах цього методу. Якщо він буде розміщений у визначенні класу, він буде мати обсяг у межах цього класу.

5
Я думав, що неможливо додати usingоператор у межах класу ...? У мене виникло те саме запитання, що і до ОП, через те, що я хотів уникати вводити std::всюди місця. У мене з’явилися заняття, в яких використовується багато векторів із розумними покажчиками, а std::префікс із п’яти символів додає велику довжину рядка - що, як мені здається, читає гірше. Тож мені було цікаво, чи нормальна usingдиректива в просторі імен, що містить клас? (Навіть якщо в шапці.)
thomthom

5
А як бути, якщо він розміщений в межах namespace { ... }?
einpoklum

Таким чином, ви можете повністю написати: {використовуючи простір імен blabla; клас бла {}; } і що використання буде застосовуватися лише до класу?
Дінаїз

8

Область є незалежною від сфери використання декларації.

Якщо це глобальна сфера, то це буде в глобальному масштабі. Якщо він знаходиться в глобальному масштабі файлу заголовка, то він буде знаходитись у загальному масштабі кожного вихідного файлу, що включає заголовок.

Отже, загальна порада - уникати використання декларацій у глобальній області файлів заголовків .


3
Це недостатньо сильно. Замініть уникнення на Не
Мартін Йорк,

1
Але уникати сильніше, ніж ні. "Уникайте ударів інших автомобілів"
bobobobo

6

У цитованому випадку файл ("блок перекладу"), що означає "так", кожен файл, що включає його.

Ви також можете помістити використовувальний оператор всередину класу, і в цьому випадку він діє саме для цього класу.

Як правило, якщо вам потрібно вказати простір імен у заголовку, найчастіше найкраще просто кваліфікувати кожен необхідний ідентифікатор.


Зауважте, що usingдекларація в класі не поводиться так само, як поза класом - наприклад, ви не можете використовувати це приведення coutзамість того, щоб std::coutпотрапляти в область класу.
Нуль

2

Це правильно. Область застосування - це модуль, який використовує usingдекларацію. Якщо будь-які файли заголовків, що містять модуль, мають usingдекларації, сфера дії цих декларацій буде таким модулем, як і будь-які інші модулі, що містять ті самі заголовки.


1

Є кілька коментарів, які є досить некваліфікованими, коли вони говорять "Не варто". Це занадто суворо, але ви повинні розуміти, коли це нормально.

Написання using std::stringніколи не буває нормально. Написання using ImplementationDetail::Fooу власному заголовку, коли цей заголовок декларує ImplementationDetail :: Foo може бути добре, тим більше, якщо використання декларації відбувається у вашому просторі імен. Напр

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
Користувач заголовка може написатиMyNS::Foo
Пітер Реммерс

Кращий приклад - це using boost::posix_time::ptime. Впевнений, що користувач може писати, MyNS::ptimeале це ще не кінець світу, і це може компенсуватися зручністю мати такі функції MyFunction(ptime a, ptime b).
Нуль

5
Чому це using std::stringніколи не нормально? Навіть у власному просторі імен зберегти багато std::префіксів?
thomthom

@thomthom це нормально, коли він знаходиться в такій області, як ваша власна область імен.
jcoffland
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.