Порядок использования пространства имен std; и включает? - PullRequest
10 голосов
/ 27 июля 2011

Я недавно видел, как этот код используется в исходном файле в проекте C ++:

using namespace std;
#include <iostream>

Игнорирование всех вопросов о том, стоит ли вообще иметь using namespace std, является ли приведенный выше код дажезаконно?В этих файлах нет кода перед этими двумя строками.

Я бы подумал, что это не скомпилируется, поскольку namespace std не был объявлен в области видимости, пока директива #include <iostream> не включит его вфайл, но с использованием системы сборки для проекта, это было прекрасно.Если у кого-то есть ссылка на соответствующую часть спецификации, это будет очень ценно.

Ответы [ 6 ]

5 голосов
/ 07 августа 2011

Возможно, интересная точка данных.Когда я компилирую следующее:

using namespace std;
using namespace no_such_namespace;

с g ++ 4.5.2, я получаю:

c.cpp:2:17: error: ‘no_such_namespace’ is not a namespace-name
c.cpp:2:34: error: expected namespace-name before ‘;’ token

Ни std, ни no_such_namespace не было определено как пространство имен в этой точкеНо g ++ жалуется только на второе.Я не думаю, что есть что-то особенное в идентификаторе std в отсутствие его объявления.Я думаю, что @James Kanze прав, что это ошибка в g ++.

РЕДАКТИРОВАТЬ: И об этом сообщалось. (5 лет назад!)

ОБНОВЛЕНИЕ: Теперь этоболее 8 лет, и до сих пор не назначен никому, тем более исправлен.g ++ 4.9.2 демонстрирует проблему.clang ++ 3.5 этого не делает, но выдает предупреждение для std и фатальную ошибку для no_such_namespace:

c.cpp:1:17: warning: using directive refers to implicitly-defined namespace 'std'
using namespace std;
                ^
c.cpp:2:17: error: expected namespace name
using namespace no_such_namespace;
                ^
1 warning and 1 error generated.
3 голосов
/ 27 июля 2011

Я не думаю, что это законно, но стандарт не на 100% ясен об этом. По сути, поиск имени (как определено в §3.4) не может найти предыдущий объявление пространства имен, потому что его нет. Все зависит ли:

using namespace std;

является объявлением пространства имен или нет. И я не вижу текст в §7.3.4, в котором говорится, что директива using объявляет назначенного Пространство имен. G ++ разрешает ваш код, но имхо, это ошибка.

2 голосов
/ 27 июля 2011

Из SO / IEC 14882: 2003

[7.3.3.9] Объект, объявленный объявлением использования, должен быть известен в контексте использования его в соответствии с его определением в точке использования-declaration. Определения, добавленные в пространство имен после объявления об использовании, не учитываются при использовании имени.

[3.4.3.2.2] Дано X :: m (где X - этообъявленное пользователем пространство имен), или учитывая :: m (где X - глобальное пространство имен), пусть S будет множеством всех объявлений m в X и в транзитивном закрытии всех пространств имен, назначенных с помощью директив using в X и егоиспользуемые пространства имен, за исключением того, что директивы using игнорируются в любом пространстве имен, включая X, непосредственно содержащее одно или несколько объявлений m.Ни одно пространство имен не ищется более одного раза при поиске имени.Если S - пустое множество, программа некорректна.В противном случае, если S имеет ровно один член или если контекст ссылки является объявлением использования (7.3.3) , S является обязательным набором объявлений m.В противном случае, если использование m не позволяет выбрать уникальное объявление из S, программа имеет некорректную форму

Так что, если это работает, это случайность и не переносимость.

1 голос
/ 07 августа 2011

Я думаю, что в стандарте есть недостаток (включая C ++ 0x) в отношении этого случая.

Имеется в разделе 3.3.6 ([basic.scope.namespace]):

Декларативная область определения пространства имен является его телом пространства имен. Потенциальная область, обозначаемая исходным именем пространства имен, представляет собой объединение декларативных областей, установленных каждым из определений пространства имен в одной и той же декларативной области с этим исходным именем пространства имен. Считается, что объекты, объявленные в теле пространства имен, являются членами пространства имен, а имена, введенные этими объявлениями в декларативную область пространства имен, называются именами членов пространства имен. Имя члена пространства имен имеет область имен. Его потенциальная область действия включает в себя пространство имен, начиная с пункта объявления имени (3.3.2) и далее; и для каждой директивы using (7.3.4), которая назначает пространство имен члена, потенциальная область действия члена включает ту часть потенциальной области применения директивы using, которая следует за пунктом объявления члена.

и

Самой внешней декларативной областью единицы перевода также является пространство имен, называемое глобальным пространством имен. Имя, объявленное в глобальном пространстве имен, имеет глобальную область имен (также называемую глобальной областью). Потенциальная область действия такого имени начинается в точке его объявления (3.3.2) и заканчивается в конце модуля перевода, который является его декларативным регионом. Имена с глобальной областью пространства имен называются глобальными именами.

Итак, namespace std является членом глобального пространства имен, и область действия имени начинается с точки объявления .

И 3.3.2 ([basic.scope.pdecl]) говорит нам:

Точка объявления имени находится сразу после его полного декларатора (пункт 8) и до его инициализатора (если есть), за исключением случаев, указанных ниже.

И ни одно из исключений не применяется к пространствам имен.

Таким образом, имя пространства имен нельзя использовать перед его декларатором , но имя пространства имен не является декларатором. К сожалению.

1 голос
/ 27 июля 2011

Этот код является неопределенным поведением [lib.using.headers]:

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

Вы ссылаетесь на std и затем включаете заголовок, который объявляет ее.Даже это все еще неопределенное поведение:

#include <string>
using namespace std;
#include <iostream>
0 голосов
/ 10 апреля 2013

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...