Заказ использования пространства имен std; и включает?

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

using namespace std;
#include <iostream>

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

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

Ответ 1

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

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++.

EDIT: И было сообщено. (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.

Ответ 2

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

using namespace std;

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

Ответ 3

От SO/IEC 14882: 2003

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

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

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

Ответ 4

Этот код undefined поведение [lib.using.headers]:

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

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

#include <string>
using namespace std;
#include <iostream>

Ответ 5

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

В разделе 3.3.6 ([basic.scope.namespace]) мы имеем:

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

и

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

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

И 3.3.2 ([basic.scope.pdecl]) сообщает нам:

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

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

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

Ответ 6

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