Это плохо или правильно сформировано в соответствии со стандартом c ++?
namespace M { struct i {}; }
namespace N { static int i = 1; }
using M::i;
using N::i;
int main() { sizeof (i); }
Clang отклоняет это, и GCC принимает это.
Согласно [namespace.udir-6] (http://eel.is/c++draft/basic.namespace#namespace.udir-6):
Если поиск имени находит объявление для имени в двух разных
пространства имен и объявления не объявляют одну и ту же сущность и делают
Не объявляйте функции, использование имени является неправильным.
Как мы должны интерпретировать это? Помните, что каждое объявление об использовании объявляет имя [namespace.udecl] p1 (http://eel.is/c++draft/namespace.udecl#1):
Объявление-использование вводит имя в декларативную область в
который появляется объявление об использовании.используя декларирование:
using typename
выбирать вложенное имя спецификатор неквалифицированный-ID;
Имя члена, указанное в объявлении об использовании, объявляется в
декларативный регион, в котором появляется объявление об использовании. [ Заметка:
Только указанное имя объявляется так; указание имени перечисления
в объявлении об использовании не объявляет свои перечислители в
декларативный регион использования-декларации. — конец примечания] Если
использование-объявления именует конструктор ([class.qual]), он неявно
объявляет набор конструкторов в классе, в котором
появляется объявление об использовании ([class.inhctor]); иначе имя
указанный в объявлении использования является синонимом для набора
объявления в другом пространстве имен или классе.
Итак, у нас есть 4 объявления имени i.
Что из этого делает поиск безусловного имени i
в sizeof(i)
находить?
Это только найти using M::i;
а также using N::i;
которые находятся в одном и том же пространстве имен (глобальном пространстве имен), поэтому программа хорошо сформирована?
Или это только найти struct i {};
а также static int i = 1;
которые находятся в разных пространствах имен, так что программа плохо сформирована?
Или у нас есть другая альтернатива?
Bogdan уже должен ответить, но чтобы понять, почему ваша интуиция неверна, вы процитировали:
Если поиск имени находит объявление для имени в два разных пространства имен, и объявления не объявляют одну и ту же сущность и не объявляют функции, использование имени неправильно сформировано.
Но в примере мы имеем:
namespace M {
struct i {}; // declares M::i, entity class type
}
namespace N {
static int i = 1; // declares N::i, entity variable
}
using M::i; // declares ::i, synonym of M::i
using N::i; // declares ::i, synonym of N::i
// hides (*) the other ::i
int main() {
sizeof (i);
}
Разработать (*)
у нас есть две декларации i
в глобальном пространстве имен ::
, Из [basic.scope.hiding]:
Имя класса (9.1) или имя перечисления (7.2) можно скрыть по имени переменной, члена данных,
Функция или перечислитель объявлены в той же области видимости. Если имя класса или перечисления и переменная, данные
член, функция или перечислитель объявляются в той же области (в любом порядке) с тем же именем,
имя класса или перечисления скрыто там, где имя переменной, члена данных, функции или перечислителя
видимый.
Так с двумя i
в той же области, класс скрыт (независимо заказа из с помощью деклараций!), а также sizeof(i)
относится к ::i
это синоним N::i
, И то и другое i
с были в так же пространство имен (::
), поэтому ваша цитата не применяется. Это отличается от вашего предыдущий вопрос, где ты был используя-директивы вместо:
using namespace M;
using namespace N;
Там i
будет найдено в двух разных пространствах имен, ссылаясь на две разные нефункциональные сущности. Отсюда и ошибка. Здесь Clang не прав, а GCC прав.
N4527 [7.3.3p13]:
Так как используя декларирование это декларация, ограничения на
объявления с одинаковыми именами в одном и том же декларативном регионе (3.3)
также относится к с помощью деклараций. [ Пример:namespace A { int x; } namespace B { int i; struct g { }; struct x { }; void f(int); void f(double); void g(char); // OK: hides struct g } void func() { int i; using B::i; // error: i declared twice void f(char); using B::f; // OK: each f is a function f(3.5); // calls B::f(double) using B::g; g(’a’); // calls B::g(char) struct g g1; // g1 has class type B::g using B::x; using A::x; // OK: hides struct B::x x = 99; // assigns to A::x struct x x1; // x1 has class type B::x }
— конец примера ]
Обратите внимание с помощью деклараций для двух разных x
s — это тот же случай, что и ваш пример.
Ваша первая цитата относится к используя-директивы, не с помощью деклараций.
Неквалифицированный поиск имени для i
в sizeof(i)
находит i
s в глобальном пространстве имен. Поскольку они являются объявлениями в одной и той же области видимости, согласно [3.3.10p2] (цитата ниже), переменная i
прячет struct
,
Имя класса (9.1) или имя перечисления (7.2) может быть скрыто по имени
переменной, члена данных, функции или перечислителя, объявленного в
та же сфера Если имя класса или перечисления и переменная, данные
член, функция или перечислитель объявляются в одной и той же области видимости (в любом
order) с тем же именем, имя класса или перечисления скрыто
где имя переменной, члена данных, функции или перечислителя
видимый.
Таким образом, код правильно сформирован, и Clang ошибочно его отвергает.
MSVC (12 и 14) принимает пример.
В основном, подумайте об имени, введенном используя декларирование как просто другое имя для некоторой сущности, которая также названа где-то еще (место, обозначенное вложенное имя спецификатор из Квалифицированный-идентификатор в используя декларирование). Это отличается от того, что с помощью директивы делает; Я склонен думать о используя-директивы как «твики поиска имени».