Относительно глобального пространства имен в C ++ - PullRequest
22 голосов
/ 05 октября 2011

В C ++ должны ли мы предвосхищать вещи в глобальном пространстве имен с помощью ::?

Например, при использовании WinAPI, который находится в C, я должен сделать ::HANDLE вместо HANDLE и ::LoadLibrary вместо LoadLibrary? Что С ++ говорит об этом? Как правило, это хорошая идея, учитывая такие вопросы, как читабельность и удобство обслуживания?

Ответы [ 7 ]

9 голосов
/ 05 октября 2011

Имена в C ++ могут быть квалифицированными и неквалифицированными.Существуют разные правила для поиска квалифицированных и неквалифицированных имен.::HANDLE является полным именем, тогда как HANDLE является неполным именем.Рассмотрим следующий пример:

#include <windows.h>

int main()
{
    int HANDLE;
    HANDLE x; //ERROR HANDLE IS NOT A TYPE
    ::HANDLE y; //OK, qualified name lookup finds the global HANDLE
}

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

7 голосов
/ 05 октября 2011

Поскольку пространства имен в C не существует, не используйте :: HANDLE для доступа к типу HANDLE.

Использование preeding :: for global namespace - хорошая идея для удобочитаемости, вы знаете, к какому типу вы хотите обращаться из глобального пространства имен.

Более того, если вы находитесь во вложенном пространстве имен и объявляете свой собственный тип HANDLE (например), то компилятор будет использовать этот вместо windows.h one!

Таким образом, всегда предпочитайте использовать :: перед именами при работе во вложенном пространстве имен.

5 голосов
/ 05 октября 2011

Основной интерес представляет то, в чем различия с точки зрения компилятора, как уже было сказано, если вы включаете ::, то вы используете квалифицированный поиск, а не неквалифицированный поиск.

Преимущество использования квалифицированного поиска состоит в том, что он всегда сможет точно определить конкретный символ.Недостатком является то, что он всегда точно определяет этот конкретный символ - то есть он отключает Argument Dependent Lookup.ADL является большой и полезной частью языка, и, квалифицируя, вы фактически отключаете его, и это плохо.

Учтите, что у вас есть функция f в глобальном пространстве имен и что вы добавили типT внутри пространства имен N.Не считайте, что вы хотели добавить перегрузку f, которая бы принимала T в качестве аргумента.Следуя принципу interface , вы можете добавить f к пространству имен N, поскольку f на самом деле является операцией, выполняемой над T, и поэтому относится к типу.В этом случае, если у вас был код, который вызывал (рассмотрим универсальный код) ::f(obj) для объекта неизвестного типа U, компилятор не сможет принять ::N::f(obj) в качестве потенциальной перегрузки, поскольку код явно запрашиваетперегрузка в глобальном пространстве имен.

Использование неквалифицированного поиска дает вам свободу определения функций, которым они принадлежат, вместе с типами, которые используются в качестве аргументов.Хотя это не совсем то же самое, рассмотрите возможность использования swap, но если вы квалифицируетесь std::swap, он не поднимет вашу руку, брошенную void swap( T&, T& ) в ваше N пространство имен ...

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

4 голосов
/ 05 октября 2011

Обычно вы не должны добавлять :: к глобальному пространству имен.(Только в некоторых действительно редких обстоятельствах).ИМХО, это вредит читабельности, но, с другой стороны, вероятно, не нарушит ваш код

4 голосов
/ 05 октября 2011

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

2 голосов
/ 12 февраля 2013

Я помещаю весь свой код в пространство имен, и я предпочитаю отдавать предпочтение заголовкам C ++, а не заголовкам C, поэтому единственные символы, оставшиеся в глобальном пространстве имен, как правило, принадлежат Windows API. Я избегаю вытягивать символы из других пространств имен в текущее пространство имен (например, у меня никогда не бывает using namespace std;), вместо этого я предпочитаю явно определять вещи. Это соответствует Руководству по стилю Google C ++ .

Поэтому у меня появилась привычка квалифицировать вызовы функций WinAPI с помощью :: по нескольким причинам:

  1. Согласованность. Для всего, что находится за пределами текущего пространства имен, я ссылаюсь на него явно (например, std::string), так почему бы не обратиться к API Windows явно (например, ::LoadLibraryW)? Пространство имен Windows API является глобальным пространством имен.

  2. Многие функции WinAPI имеют общие названия (например, DeleteObject). Если вы не очень хорошо знакомы с кодом, который читаете, вы можете не знать, является ли DeleteObject вызовом чего-либо в текущем пространстве имен или в Windows API. Таким образом, я нахожу :: уточнения.

  3. Многие платформы Windows имеют методы с такими же именами, что и необработанные вызовы. Например, ATL::CWindow имеет метод GetClientRect с несколько отличной сигнатурой, чем GetClientRect в WinAPI. В этой среде ваш класс является производным от ATL::CWindow, поэтому в реализации вашего класса обычно говорят GetClientRect для вызова унаследованного метода ATL и ::GetClientRect, если вам нужно вызвать функцию WinAPI. Это не является строго обязательным, поскольку компилятор найдет правильный на основе сигнатуры. Тем не менее, я считаю, что различие проясняется для читателя.

(я знаю, что вопрос не был действительно о WinAPI, но пример был с точки зрения WinAPI.)

1 голос
/ 05 октября 2011

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

...