Я не думаю, что кто-то из них плохо сформирован. Во-первых, для using X::f2
ищется X
, и это однозначно даст тип класса X
. Затем ищется f2
в X
, и это тоже однозначно (в D
не ищется!).
Второй случай будет работать по той же причине.
Но если вы вызовете f2
для объекта D
, вызов будет неоднозначным, поскольку имя f2
ищется во всех подобъектах D
типа X
, а D
имеет два таких подобъекта, а f2
является нестатическая функция-член. Та же причина справедлива и для второго случая. Для этого не имеет значения, называете ли вы f3
напрямую через Z::X
или X
. Оба они обозначают класс X
.
Чтобы получить неоднозначность объявления использования, вам нужно написать его по-другому. Обратите внимание, что в C++0x using ThisClass::...;
недопустимо. Однако это в С++ 03, если все имя относится к члену базового класса.
И наоборот, если бы это было разрешено в C++0x, все объявление using также было бы действительным, поскольку C++0x не учитывает подобъекты при поиске по имени: D::f2
однозначно относится только к одному объявлению em> (тот, что в 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, и задним числом реализуют эту формулировку:
В объявлении-использования, используемом в качестве объявления-члена, спецификатор вложенного-имени должен называть базовый класс определяемого класса.
Это означает, что небазовые классы учитываются, но если указан небазовый класс, это будет ошибкой. Если бы Стандарт намеревался игнорировать имена небазовых классов, он сказал бы здесь can only или указал бы это явно (оба метода выполняются). Однако Стандарт вовсе не является следствием использования в нем слов должен и может. И GCC реализует формулировку C++0x, потому что он отвергает совершенно прекрасный код C++03, просто потому, что объявление using содержит его имя класса.
В качестве примера неясной формулировки рассмотрим следующее выражение:
a.~A();
Это синтаксически неоднозначно, потому что это может быть вызов функции-члена, если a
является объектом класса, но это может быть вызов псевдодеструктора (который не является операцией), если a
имеет скалярный тип (например, int
). Но то, что говорит Стандарт, касается синтаксиса вызова псевдодеструктора и доступа к члену класса в 5.2.4
и 5.2.5
соответственно.
Левая часть оператора точки должна быть скалярного типа.
Для первого варианта (точка) тип первого выражения (выражения объекта) должен быть «объект класса» (полного типа).
Это неправильное использование, потому что оно вообще не устраняет двусмысленность. Он должен использовать только can, и компиляторы интерпретируют его таким образом. У этого в основном исторические причины, как недавно сказал мне один член комитета в юзнете. См. Правила структуры и составления международных стандартов, Приложение H.
person
Johannes Schaub - litb
schedule
23.08.2010