Яка сфера застосування "використання" в 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.