On Mon, 10 Oct 2005 10:34:15 +0400, Шахтер <23118@users.rsdn.ru> wrote:
> Здравствуйте, MaximE, Вы писали: > > ME>Здравствуйте, Шахтер, Вы писали: > > Ш>>Здравствуйте, the_void, Вы писали: > > _>>>Здравствуйте, Шахтер, Вы писали: > > Ш>>>>Поставил себе бету. Сразу напоролся на два бага. > > _>>><skip> > > _>>>Первая ошибка вроде вполне законна Comeau этот код не компилирует. > > Ш>>Позор Comeau. > > ME>Comeau прав, это твоя ошибка. > > С какого это перепугу он прав?
3.4.1 Unqualified name lookup [basic.lookup.unqual]
1 In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.
...
7 A name used in the definition of a class X outside of a member function body or nested class definition shall be declared in one of the following ways:
...
— if X is a nested class of class Y (9.7), before the definition of X in Y, or shall be a member of a base class of Y (this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class)
or
...
Т.е. здесь применяется обычный name lookup. Определение базового класса А для вложенного класса C::I ищется согласно 3.4.1 сначала в C, затем в базовых классах C. Это имя находится в scope'e базового класса B. Как только имя найдено процесс поиска имени закончен. Далее делается проверка доступа и завершается с ошибкой, так как A — private базовый класс B.
Тонкость, которую не стоит упускать: поиск имени и проверка доступа — последовательные независимые этапы.
Здравствуйте, Andrew S, Вы писали:
ПК>>С впрыскиванием имени класса в его scope: http://tydbits.org/node/62
AS>Павел, а можно привести разъяснения для С++ варианта? Очень заинтриговало
Здравствуйте, the_void, Вы писали:
_>Здравствуйте, Шахтер, Вы писали:
Ш>>Поставил себе бету. Сразу напоролся на два бага.
_><skip>
_>Первая ошибка вроде вполне законна Comeau этот код не компилирует.
Позор Comeau.
_>Вторая ошибка не воспроизводится (VC 8.0 beta 2).
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, the_void, Вы писали:
_>>>Здравствуйте, Шахтер, Вы писали:
Ш>>>>Поставил себе бету. Сразу напоролся на два бага.
_>>><skip>
_>>>Первая ошибка вроде вполне законна Comeau этот код не компилирует.
Ш>>Позор Comeau.
ME>Comeau прав, это твоя ошибка.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Шахтер,
>>
>> /* Bug1 */
>>
>> class A {};
>>
>> class B : A { };
>>
>> class C : public B
>> {
>> public:
>> class I : A {};
>> };
>>
>>
>> .\test1.cpp(19) : error C2247: 'A' not accessible because 'B' uses 'private' to inherit from 'A'
>> .\test1.cpp(9) : see declaration of 'A'
>> .\test1.cpp(11) : see declaration of 'B'
>> .\test1.cpp(9) : see declaration of 'A'
>>
ПК>Это не баг, это следствие базовых положений: ПК> проверка доступа контролируется на уровне имен, а не обозначаемых ими сущностей; ПК> имя класса впрыскивается в его scope и наследуется; ПК> имя из class scope перекрывает имена из global scope.
Спасибо, я уже тоже нашел.
ПК>Почему полезно впрыскивать имя класса в его scope.
Полезно, согласен. Но в данном случае, однако, получается фигня-с -- хвост вылез, клюв застрял. Надо дефект репорт писать.
Например, добавить в пункт 3.4 3 следующее положение про применение правил доступа.
The injected-class-name of a class (clause 9) is also considered to be a member of that class for the purposes
of name hiding and lookup.
To check accessibility of this name access rules are applyed not to the injected-class-name, but to the original class name.
/* test1.cpp */#include <iostream>
using namespace std;
/* Bug1 */class A {};
class B : A
{
};
class C : public B
{
public:
class I : A {};
};
.\test1.cpp(19) : error C2247: 'A' not accessible because 'B' uses 'private' to inherit from 'A'
.\test1.cpp(9) : see declaration of 'A'
.\test1.cpp(11) : see declaration of 'B'
.\test1.cpp(9) : see declaration of 'A'/* Bug2 */template <class T>
struct Foo
{
};
template <size_t N>
struct Foo<const char[N]>
{
enum { Ret=100 };
};
template <class T,size_t N>
struct Foo<const T[N]>
{
};
template <class T>
int GetFoo(const T &)
{
return Foo<T>::Ret;
}
/* main() */int main()
{
cout << GetFoo("12345") << endl ;
return 0;
}
.\test1.cpp(43) : error C2752: 'Foo<T>' : more than one partial specialization matches the template argument list
with
[
T=const char [6]
]
.\test1.cpp(38): could be 'Foo<const T[N]>'
.\test1.cpp(33): or 'Foo<const char [N]>'
.\test1.cpp(50) : see reference to function template instantiation 'int GetFoo<const char[6]>(T (&))' being compiled
with
[
T=const char [6]
]
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, the_void, Вы писали:
_>>Здравствуйте, Шахтер, Вы писали:
Ш>>>Поставил себе бету. Сразу напоролся на два бага.
_>><skip>
_>>Первая ошибка вроде вполне законна Comeau этот код не компилирует.
Ш>Позор Comeau.
Здравствуйте, MaximE, Вы писали:
ME>On Mon, 10 Oct 2005 10:34:15 +0400, Шахтер <23118@users.rsdn.ru> wrote:
>> Здравствуйте, MaximE, Вы писали: >> >> ME>Здравствуйте, Шахтер, Вы писали: >> >> Ш>>Здравствуйте, the_void, Вы писали: >> >> _>>>Здравствуйте, Шахтер, Вы писали: >> >> Ш>>>>Поставил себе бету. Сразу напоролся на два бага. >> >> _>>><skip> >> >> _>>>Первая ошибка вроде вполне законна Comeau этот код не компилирует. >> >> Ш>>Позор Comeau. >> >> ME>Comeau прав, это твоя ошибка. >> >> С какого это перепугу он прав?
ME>
ME>3.4.1 Unqualified name lookup [basic.lookup.unqual]
ME>1 In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.
ME>...
ME>7 A name used in the definition of a class X outside of a member function body or nested class definition shall be declared in one of the following ways:
ME>...
ME>— if X is a nested class of class Y (9.7), before the definition of X in Y, or shall be a member of a base class of Y (this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class)
ME>or
ME>...
ME>Т.е. здесь применяется обычный name lookup. Определение базового класса А для вложенного класса C::I ищется согласно 3.4.1 сначала в C, затем в базовых классах C. Это имя находится в scope'e базового класса B. Как только имя найдено процесс поиска имени закончен. Далее делается проверка доступа и завершается с ошибкой, так как A — private базовый класс B.
Класс A определён не в scope класса B, а в глобальном scope. Его полное имя ::A, а не ::B::A. Так что не проходит твоё рассуждение.
Но дело даже не в этом -- сама ситуация абсурдна, когда некий промежуточный класс переквалифицировал возможность использования класса из глобалбного пространства имен.
ME>Тонкость, которую не стоит упускать: поиск имени и проверка доступа — последовательные независимые этапы.
ME>-- ME>Maxim Yegorushkin
Здравствуйте, Lorenzo_LAMAS, Вы писали:
Ш>>С какого это перепугу он прав? L_L>Почитай про поиск имен, а потом про доступ. Если напишешь ::А то скомпилит.
A и ::A обозначают одну и ту же сущность -- класс A определённый в глобальном пространстве имен.
On Mon, 10 Oct 2005 19:50:13 +0400, Шахтер <23118@users.rsdn.ru> wrote:
[]
> ME>Т.е. здесь применяется обычный name lookup. Определение базового класса А для вложенного класса C::I ищется согласно 3.4.1 сначала в C, затем в базовых классах C. Это имя находится в scope'e базового класса B. Как только имя найдено процесс поиска имени закончен. Далее делается проверка доступа и завершается с ошибкой, так как A — private базовый класс B. > > Класс A определён не в scope класса B, а в глобальном scope. Его полное имя ::A, а не ::B::A.
Это так.
> Так что не проходит твоё рассуждение.
Подходит, читай ниже.
> Но дело даже не в этом -- сама ситуация абсурдна, когда некий промежуточный класс переквалифицировал возможность использования класса из глобалбного пространства имен.
Вот здесь корень твоего заблуждения. Именно в этом вся суть пространств имен — чтобы в них можно было объявлять те же имена, что и в других scope'aх. Class — это то же (кастрированное) пространство имен.
Поиск неквалифицированных имен не ищет объявление. Он ищет первый scope, в котором это имя доступно. scope, в котором имя объявлено, всего лишь один, в которых оно доступно — один и более.
Считаешь ли ты такую ситуацию абсурдной:
struct A {};
namespace B
{
struct A {};
namespace C
{
struct I : A {}; // I derives B::A, not ::A
}
}
?
P.S. Вобщем-то, мне все равно, что ты считаешь — меня не беспокоит чужое неправильное понимание, отвечать в этом треде я больше не буду.
Здравствуйте, MaximE, Вы писали:
ME>On Mon, 10 Oct 2005 19:50:13 +0400, Шахтер <23118@users.rsdn.ru> wrote:
ME>[]
>> ME>Т.е. здесь применяется обычный name lookup. Определение базового класса А для вложенного класса C::I ищется согласно 3.4.1 сначала в C, затем в базовых классах C. Это имя находится в scope'e базового класса B. Как только имя найдено процесс поиска имени закончен. Далее делается проверка доступа и завершается с ошибкой, так как A — private базовый класс B. >> >> Класс A определён не в scope класса B, а в глобальном scope. Его полное имя ::A, а не ::B::A.
ME>Это так.
>> Так что не проходит твоё рассуждение.
ME>Подходит, читай ниже.
>> Но дело даже не в этом -- сама ситуация абсурдна, когда некий промежуточный класс переквалифицировал возможность использования класса из глобалбного пространства имен.
ME>Вот здесь корень твоего заблуждения. Именно в этом вся суть пространств имен — чтобы в них можно было объявлять те же имена, что и в других scope'aх. Class — это то же (кастрированное) пространство имен.
ME>Поиск неквалифицированных имен не ищет объявление.
Противоречие однако. Если суть -- в возможности объявлять, то и искаться должны объявления.
ME>Он ищет первый scope, в котором это имя доступно. scope, в котором имя объявлено, всего лишь один, в которых оно доступно — один и более.
ME>Считаешь ли ты такую ситуацию абсурдной:
ME>
ME>struct A {};
ME>namespace B
ME>{
ME> struct A {};
ME> namespace C
ME> {
ME> struct I : A {}; // I derives B::A, not ::A
ME> }
ME>}
ME>
ME>?
Эта ситуация нормальна -- именно потому, что пространство имен B объявляет своё имя A, которое скрывает имя, определённое в глобальном scope. В моём же случае этого нет. И в этом большая разница.
ME>P.S. Вобщем-то, мне все равно, что ты считаешь — меня не беспокоит чужое неправильное понимание, отвечать в этом треде я больше не буду.
Спасибо за потраченное на ответы время.
ME>-- ME>Maxim Yegorushkin
> /* Bug1 */
>
> class A {};
>
> class B : A { };
>
> class C : public B
> {
> public:
> class I : A {};
> };
>
>
> .\test1.cpp(19) : error C2247: 'A' not accessible because 'B' uses 'private' to inherit from 'A'
> .\test1.cpp(9) : see declaration of 'A'
> .\test1.cpp(11) : see declaration of 'B'
> .\test1.cpp(9) : see declaration of 'A'
>
Это не баг, это следствие базовых положений:
проверка доступа контролируется на уровне имен, а не обозначаемых ими сущностей;
имя класса впрыскивается в его scope и наследуется;
имя из class scope перекрывает имена из global scope.
Почему полезно впрыскивать имя класса в его scope.
Помимо прочего, для того, чтобы имя обозначало один и тот же класс, как в списке базовых классов, так и внутри класса. Например:
Ш>A и ::A обозначают одну и ту же сущность -- класс A определённый в глобальном пространстве имен.
Несомненно. Вот только просто А будет найдено как имя где-то в базовых классах, да еще и закрытое, а ::А будет сразу искаться в глобальном пространстве имен.
Of course, the code must be complete enough to compile and link.
Здравствуйте, Andrew S, Вы писали:
ПК>>С впрыскиванием имени класса в его scope: http://tydbits.org/node/62
AS>Павел, а можно привести разъяснения для С++ варианта? Очень заинтриговало
template <class T1>
struct A
{
T1 a;
template <class T2>
struct B : A<T2> // (1)
{
T1 b;
template <class T3>
struct C : B<T3> // Что означает B здесь?
{
T1 c;
};
};
};
B в указанной точке должно означать A<что-то>::B.
Есть два варианта. Первый(правильный) -- A<T1>::B.
Второй -- A<T2>::B. Второй вариант получается из-за наследования (1).
Срабатывает первый вариант, потому что в scope B вводится имя B -- A<T1>::B, которое перекрывает имя, унаследованное из базового класса. В С# происходит обратное.
Здесь правда есть ещё одна тонкость -- независимые имена. В декларации класса C имя B может быть связано только с именем A<T1>::B, поскольку имя A<T2>::B, унаследованное из A<T2>, найдено быть не может в точке декларации шаблона.
Так что в C++ дело не доходит даже до сокрытия имени.
Ш>template <class T1>
Ш>struct A
Ш> {
Ш> T1 a;
Ш> template <class T2>
Ш> struct B : A<T2> // (1)
Ш> {
Ш> T1 b;
Ш> template <class T3>
Ш> struct C : B<T3> // Что означает B здесь?
Ш> {
Ш> T1 c;
Ш> };
Ш> };
Ш> };
Ш>
Ш>B в указанной точке должно означать A<что-то>::B.
Ш>Есть два варианта. Первый(правильный) -- A<T1>::B. Ш>Второй -- A<T2>::B. Второй вариант получается из-за наследования (1). Ш>Срабатывает первый вариант, потому что в scope B вводится имя B -- A<T1>::B, которое перекрывает имя, унаследованное из базового класса. В С# происходит обратное.
Разве тут дело в сокрытии? Что тут может (в случае С++) скрываться, если B — это шаблонный класс, соответственно для каждого типа генерируется свой инстанс. По-моему, дело в том, как определяется параметр T1.
Попробуем инстанцировать A<int>::B<bool>::C<char>:
Очевидно, что тут T1 определяется из внешнего по отношению к типу неймспейса, которым в данном случае на всех шагах служит А (поскольку в параметрах B и С мы T1, естественно, не находим).
Ш>Здесь правда есть ещё одна тонкость -- независимые имена. В декларации класса C имя B может быть связано только с именем A<T1>::B, поскольку имя A<T2>::B, унаследованное из A<T2>, найдено быть не может в точке декларации шаблона. Ш>Так что в C++ дело не доходит даже до сокрытия имени.
Про то и речь. О каком сокрытии имен может идти речь, если тут шаблонные классы. На мой взгляд, все дело в лукапе параметров шаблона. Лучше пусть ПК объяснит, это все он виноват
Здравствуйте, MaximE, Вы писали:
ME>On Mon, 10 Oct 2005 19:50:13 +0400, Шахтер <23118@users.rsdn.ru> wrote:
ME>[]
>> ME>Т.е. здесь применяется обычный name lookup. Определение базового класса А для вложенного класса C::I ищется согласно 3.4.1 сначала в C, затем в базовых классах C. Это имя находится в scope'e базового класса B. Как только имя найдено процесс поиска имени закончен. Далее делается проверка доступа и завершается с ошибкой, так как A — private базовый класс B. >> >> Класс A определён не в scope класса B, а в глобальном scope. Его полное имя ::A, а не ::B::A.
ME>Это так.
>> Так что не проходит твоё рассуждение.
ME>Подходит, читай ниже.
>> Но дело даже не в этом -- сама ситуация абсурдна, когда некий промежуточный класс переквалифицировал возможность использования класса из глобалбного пространства имен.
ME>Вот здесь корень твоего заблуждения. Именно в этом вся суть пространств имен — чтобы в них можно было объявлять те же имена, что и в других scope'aх. Class — это то же (кастрированное) пространство имен.
ME>Поиск неквалифицированных имен не ищет объявление. Он ищет первый scope, в котором это имя доступно. scope, в котором имя объявлено, всего лишь один, в которых оно доступно — один и более.
Придётся ещё раз ответить
Не доступно, а видимо. Это принципиальная разница. Если он искал доступное имя, то нашёл бы как раз ::A.
[]
ME>>Поиск неквалифицированных имен не ищет объявление. Он ищет первый scope, в котором это имя доступно. scope, в котором имя объявлено, всего лишь один, в которых оно доступно — один и более.
R>Придётся ещё раз ответить R>Не доступно, а видимо. Это принципиальная разница. Если он искал доступное имя, то нашёл бы как раз ::A.
Здесь "доступно" имелось ввиду на этапе поиска имени, а не на более позднем этапе проверки доступности private/public. Простите за неточность.
Ну то есть, фактически, нас интересует только та часть, где инстанцируется C. При чем здесь сокрытие имен, как говорил Шахтер, когда, на мой взгляд, тут просто банальный резолвинг параметра из внешнего неймспейса?