Порядок использования пространства имен std; и включает?
недавно я видел, как этот код используется в исходном файле в проекте C++:
using namespace std;
#include <iostream>
игнорируя все вопросы о том, является ли это хорошей идеей иметь using namespace std
вообще, является ли вышеуказанный код даже законным? В файле нет кода перед этими двумя строками.
Я бы подумал, что это не будет компилироваться, так как namespace std
не было объявлено в области до #include <iostream>
директива включает его в файл, но с помощью системы сборки для проекта это компилируется только штраф. Если у кого-то есть ссылка на соответствующую часть спецификации, это было бы наиболее оценено.
6 ответов
возможно, интересная точка данных. Когда я компилирую следующее:
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 лет назад!)
UPDATE: теперь это больше, чем 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.
Я не думаю, что это законно, но уровень не 100% понятно. В принципе, поиск имени (как определено в §3.4) не может найти предыдущий объявление пространства имен, потому что его нет. Всё зависит от того:
using namespace std;
является объявлением пространства имен или нет. И я не вижу никакого текста в §7.3.4 в котором говорится, что директива использования объявляет назначенный пространство имен. G++ позволяет ваш код, но IMHO, это ошибка.
из SO / IEC 14882: 2003
[7.3.3.9] сущность, объявленная декларацией использования, должна быть известна в контексте, использующем ее, в соответствии с ее определением в точке декларации использования. определения, добавленные в пространство имен после объявления using, не учитываются при использовании имени.
[3.4.3.2.2] учитывая X:: m (где X-объявленное пользователем пространство имен) или учитывая ::m( где X-глобальное пространство имен), пусть S - набор всех деклараций о м в X и в транзитивное замыкание всех пространств имен, выдвинутых с помощью директив X и ее использовать пространства имен, за исключением того, что с помощью директивы игнорируются в любом пространстве имен, включая X, непосредственно содержащие одну или несколько заявлений м. Имен не искали не раз в поиске имени. Если S-пустое множество, то программа плохо сформирована. В противном случае, если S имеет ровно один член, или если контекст ссылки является объявлением using - (7.3.3), S-необходимый набор объявлений m. В противном случае, если использование m не позволяет выбрать уникальное объявление из S, программа плохо сформирована
поэтому, если это сработает, это случайность, а не портативный.
этот код является неопределенным поведением [lib.с помощью.headers]:
единица перевода должна включать заголовок только вне любого внешнего объявления или определения и должна включать заголовок лексически перед первой ссылкой на любую из сущностей, которые она объявляет или определяет в этой единице перевода.
ссылка std
и затем включите заголовок, который объявляет его. Даже это все еще неопределенное поведение:
#include <string>
using namespace std;
#include <iostream>
Я думаю, что есть недостаток в стандарте (включая C++0x) в отношении этого случая.
мы имеем в разделе 3.3.6 ([basic.scope.namespace]
):
декларативной областью определения пространства имен является его тело пространства имен. Масштаб обозначается оригинал-имен имя является объединение декларативного регионов, установленных в каждом из имен-определений в одной декларативной области с оригинальных имен-имя. Объекты, объявленные в namespace-body называются членами пространства имен, а имена, введенные этими объявлениями в декларативную область пространства имен, называются именами членов пространства имен. Имя члена пространства имен имеет область пространства имен. Его потенциальная область включает пространство имен от точки объявления имени (3.3.2) и далее; и для каждой директивы using-directive (7.3.4), которая назначает пространство имен члена, потенциальная область члена включает ту часть потенциальной области using-директива, которая следует за точкой объявления члена.
и
внешняя декларативная область единицы перевода также является пространством имен, называемым глобальным пространством имен. Имя, объявленное в глобальном пространстве имен, имеет глобальную область пространства имен (также называемую глобальной областью). Потенциальная область применения такого названия начинается в точке объявления (3.3.2) и заканчивается в конце единицы перевода, являющейся ее декларативной областью. Имена с мировой область пространства имен называется глобальным именем.
Так namespace std
является членом глобального пространства имен и области имени начинается с пункт декларации.
и 3.3.2 ([basic.scope.pdecl]
) говорит нам:
точка объявления имени находится сразу после его полного Декларатора (пункт 8) и перед его инициализатором (если таковой имеется), за исключением случаев, указанных ниже.
и ни одно из исключений не применяется к пространство имен.
таким образом, имя пространства имен не может использоваться до его Декларатор, но имя пространства имен не Декларатор. Ой.
недавно я столкнулся с той же проблемой и был уведомлен моим техническим руководством, что; использование пространства имен не гарантирует видимость методов, пока пространство имен со связанными методами не будет включено в файл с помощью .H-файл. в том числе файл заголовка решил проблему.