Я не думаю, что что-то из этого плохо сформировано.Во-первых, для using X::f2
ищется X
, и это однозначно приведет к типу класса X
.Затем ищется f2
в X
, и это тоже недвусмысленно (в D
! Это не ищется).
Второй случай будет работать по той же причине.
Но если вы вызовите f2
для объекта D
, вызов будет неоднозначным, поскольку имя f2
ищется во всех подобъектах типа D
X
, D
имеет два таких подобъекта, а f2
является нестатической функцией-членом.Та же самая причина имеет место для второго случая.Для этого не имеет значения, назовите ли вы f3
, используя Z::X
или X
напрямую.Оба они обозначают класс X
.
Чтобы получить неоднозначность для объявления использования, вам нужно написать его по-другому.Обратите внимание, что в C ++ 0x using ThisClass::...;
недопустимо.Хотя это в C ++ 03, пока все имя относится к члену базового класса.
И наоборот, если бы это было разрешено в C ++ 0x, то все объявление using также было бы допустимым, поскольку C ++ 0x не учитывает подобъекты для поиска по имени: D::f2
однозначно ссылается натолько одна декларация (одна в X
).См. DR # 39 и окончательный документ N1626 .
struct D : Y, Z{
// ambiguous: f2 is declared in X, and X is a an ambiguous base class
using D::f2;
// still fine (if not referred to by calls/etc) :)
using Z::X::f3;
};
struct E : D {
// ambiguous in C++03
// fine in C++0x (if not referred to by an object-context (such as a call)).
using D::f2;
};
Стандарт C ++ 03 описывает это в параграфах 10.2
и 3.4.3.1
.
Ответ для Edit3 :
Да, GCC и VS2010 неверны.trouble
относится к типу, найденному по введенному имени класса ::trouble
, и к вложенному классу, найденному как Y::trouble
.Имя trouble
, предшествующее ::
, ищется с использованием неквалифицированного поиска (3.4.1/7
, который делегирует 10.2
в первом маркере), игнорируя любые имена объектов, функций и перечислителей (3.4.3/1
- таких нетимена в этом случае, правда).Затем он нарушает требование 10.2
о том, что:
Если результирующий набор объявлений не все из подобъектов одного типа ... программа некорректна.
Возможно, что VS2010 и GCC интерпретируют формулировку C ++ 0x иначе, чем Comeau, и задним числом реализуют эту формулировку:
В объявлении использования, используемом в качестве члена-declaration, спецификатор вложенного имени должен называть базовый класс определяемого класса.
Это означает, что неосновные классы считаются , но это ошибка, если назван не базовый класс.Если бы стандарт намеревался игнорировать неосновные имена классов, он сказал бы, что может только здесь, или излагает это явно (обе практики выполнены).Стандарт, однако, вовсе не является следствием использования , и , может .И GCC реализует формулировку C ++ 0x, потому что в противном случае он полностью отклоняет код C ++ 03, просто потому что объявление using содержит свое имя класса.
В качестве примера неясной формулировки рассмотрим следующее выражение:
a.~A();
Это синтаксически неоднозначно, поскольку это может быть вызов функции-члена, если a
является объектом класса,но это может быть псевдо-деструктор-вызов (который не используется), если a
имеет скалярный тип (например, int
).Но в стандарте говорится о синтаксисе вызова псевдодеструктора и доступа к членам класса в 5.2.4
и 5.2.5
соответственно
Левая часть оператора точки должна быть скалярнойtype.
Для первой опции (точка) типом первого выражения (выражения объекта) должен быть «объект класса» (полного типа).
То естьнеправильное использование, потому что это не устраняет двусмысленность вообще.Он должен использовать «только», и компиляторы интерпретируют это таким образом.Это в основном исторические причины, как недавно сказал мне один из членов комитета по usenet.См. Правила составления и составления международных стандартов , Приложение H.