Не мисля, че някой от тях е неправилно оформен. Първо, за 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, цялата декларация за използване също би била валидна, тъй като 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 и със задна дата прилагат тази формулировка:
В декларация за използване, използвана като декларация за член, спецификаторът на вложеното име трябва да наименува базов клас на дефинирания клас.
Това означава, че небазовите класове са взети под внимание, но е грешка, ако се наименува небазов клас. Ако стандартът възнамерява да игнорира имена на неосновни класове, тук ще каже може само или ще го изпише изрично (и двете практики са готови). Стандартът обаче изобщо не е последователен с използването на трябва и може. И GCC прилага C++0x формулировката, защото отхвърля иначе напълно фин C++03 код, само защото използващата декларация съдържа неговото име на клас.
За пример на неясна формулировка разгледайте следния израз:
a.~A();
Това е синтактично двусмислено, защото може да бъде извикване на членска функция, ако a
е обект от клас, но може да бъде извикване на псевдо-деструктор (което е no-op), ако a
има скаларен тип (като int
). Но това, което стандартът казва, е за синтаксиса на извикване на псевдодеструктор и достъп на член на класа съответно на 5.2.4
и 5.2.5
Лявата страна на оператора точка трябва да бъде от скаларен тип.
За първата опция (точка) типът на първия израз (обектният израз) трябва да бъде „обект от клас“ (от пълен тип).
Това е грешна употреба, защото изобщо не изяснява неяснотата. Трябва да използва само can и компилаторите го интерпретират по този начин. Това има предимно исторически причини, както наскоро ми каза един член на комисия в usenet. Вижте Правилата за структурата и съставянето на международните стандарти, Приложение H.
person
Johannes Schaub - litb
schedule
23.08.2010