Использовать `using` в C ++ или избегать этого?

17

Обесценивая слегка различную семантику из-за ADL, как я должен вообще использовать usingи почему? Это зависит от ситуации (например, заголовок, который будет #included против исходного файла, который не будет)?

Кроме того, я должен предпочесть ::std::или std::?

  1. Уровень пространства имен using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Быть полностью явным:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Объявления использования на уровне пространства имен:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Функциональные объявления использования:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Функция локальная using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Что-то другое?

Это предполагает pre-C ++ 14 и, таким образом, не использует возврат типа возврата auto.

user541686
источник
2
См. Stackoverflow.com/questions/1265039/using-std-namespace для начальной точки.
AProgrammer
@AProgrammer: Ах, спасибо за ссылку, которая отвечает на часть моего вопроса. :) Все еще задаюсь вопросом о ::std::против std::хотя.
user541686
4
Я использую stdбез второго, хотя. Кто-то, определяющий пространство имен std, напрашивается на неприятности (и, вероятно, ищет преимущества, которые использует большинство людей, stdа не нет ::std).
AProgrammer

Ответы:

25

Избегайте использования usingв заголовках, потому что это нарушает назначение пространств имен.

Можно использовать его в исходных файлах, но в некоторых случаях я бы все же избегал его (например using std).

Однако, если у вас есть вложенные пространства имен, все в порядке:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A
BЈовић
источник
6
+1 Удивительно, как много учебников и курсов колледжей просто говорят вам использовать usingключевое слово без подробного объяснения того, почему пространства имен используются для начала.
Джеффри Суини
Люди хотят продолжать использовать iostreams, строки и так далее. Им не нужно вводить std :: каждый раз, когда они хотят что-то использовать, или им приходится запоминать еще один кусочек шаблона перед своим кодом, который вызовет менее полезные ошибки, если они забудут об этом. , :(
Colen
Будет что-то вроде typedef std :: string sstring; быть альтернативой?
Джорджио
1
@Colen: Эти бедные души могут использовать using std::coutи друзья, но это не так, как coutэто уже ужасно длинное имя.
Бенджамин Банье
1
Если вы студент первого курса «моего первого урока C ++», это может вызвать синтаксические ошибки, которые вы не понимаете. Нам легко понять, потому что мы опытные программисты, но когда вы пытаетесь выучить язык, вам нужно беспокоиться о том, что вам не нужно.
Colen
11

Когда вы помещаете оператор использования в исходный файл, ПОЖАЛУЙСТА, просто извлеките то, что вам нужно. Например:

using std::string;
using std::ostringstream;

Проблема в том, что если вы делаете

using namespace std;

вы вводите КАЖДУЮ ОДНУ ВЕЩЬ из std в глобальное пространство имен. Что приводит к очень интересным сообщениям об ошибках, когда вы случайно используете имя в вашем коде, совпадающее с тем, которое вы совершенно не знали в std. Если вы просто добавите то, что хотите, то у вас не будет этой проблемы (или, точнее, у следующего программиста, работающего над вашим кодом, такой проблемы не будет).

Майкл Кон
источник
В качестве альтернативы, вы можете using namespaceпросто в области действия функции, избегая проблемы.
Тамас Селеи
2
@fish - на самом деле, использование «пространства имен» в области действия функции не устраняет проблему, а лишь ограничивает пространство, в котором все может пойти не так. И если в конечном итоге вы добавите «использование пространства имен» в каждую функцию, это не сильно отличается от того, чтобы делать это глобально.
Майкл Кохн
Хотя C ++ действительно позволяет объявлять типы на уровне функций, это не обычное явление; кроме этого, возможные конфликты имен легко обнаружить по выходным данным компилятора (но вы правы, что это не мешает им).
Тамас Селеи
2

Как указывает VJovic, не используйте usingв заголовочном файле. usingв заголовочном файле влияет на текущий модуль компиляции (файл .cpp) таким образом, чего исходный файл может не ожидать.

using namespaceтакже следует избегать в исходном файле. Это приводит каждый символ в ту же область, что и исходный файл. Читателям станет понятнее, что вы делаете, если используете определенные символы из пространства имен.

Билл Дверь
источник
2
Практически, если ваш код не переопределяет часто используемые имена, я бы предпочел видеть using namespace JoystickModuleв начале файла .cpp, а не JoystickModule::прикреплять его к каждому объекту.
Алекс П
@AlexP: Именно так я и делаю. Одно usingутверждение для моего собственного пространства имен, над которым я сейчас работаю, а все остальное остается пространством имен.
Бенджамин Клостер
Я должен уточнить «использовать определенные символы из пространства имен». Вместо префикса каждого символа при каждом использовании, что не помогает с удобочитаемостью, я предпочитаю использовать явное отображение символов. using SomeNameSpace::SomeSymbol, Это позволяет избежать перемещения каждого символа из пространства имен в текущую область.
Билл Дверь
0

Запись usingв заголовках - лучший способ создавать всевозможные неприятные и невозможные отладки ошибок. Вы не делать этого.

Запись using namespace XYZв исходном файле немного лучше, но все же может вызвать у вас бесчисленные головные боли. Безопасный способ - явно указать, что вы используете, например using Foo::Bar.

Допустим, у вас есть Bar.cpp со следующим:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

Функция работала нормально, пока в один прекрасный день - казалось бы, без каких-либо изменений кода в соответствующих классах - ее поведение изменилось: внезапно currentIndexвсегда кажется, что один выключен . При просмотре последних изменений вы не обнаружите никаких изменений, даже отдаленно связанных с кодом.

В конце концов вы обнаружите причину:
вы (косвенно) включаете Foo.hкуда-то. В файлах для пространства имен Foo была добавлена ​​новая функция:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Что однозначно лучше подходит для increment(int)вашей функции, increment(double)так что теперь Foo::increment()функция вызывается Bar::someFunction()вместо. Упс.

(И если бы вы писали usingв заголовках, которые using namespace Fooвполне могли бы быть где угодно в вашем дереве включения ...)

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

CharonX
источник