/* 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.
_>Вторая ошибка не воспроизводится (VC 8.0 beta 2).
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, the_void, Вы писали:
_>>Здравствуйте, Шахтер, Вы писали:
Ш>>>Поставил себе бету. Сразу напоролся на два бага.
_>><skip>
_>>Первая ошибка вроде вполне законна Comeau этот код не компилирует.
Ш>Позор Comeau.
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, the_void, Вы писали:
_>>>Здравствуйте, Шахтер, Вы писали:
Ш>>>>Поставил себе бету. Сразу напоролся на два бага.
_>>><skip>
_>>>Первая ошибка вроде вполне законна Comeau этот код не компилирует.
Ш>>Позор Comeau.
ME>Comeau прав, это твоя ошибка.
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.
Тонкость, которую не стоит упускать: поиск имени и проверка доступа — последовательные независимые этапы.
Здравствуйте, 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.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Шахтер,
>>
>> /* 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.
Здравствуйте, 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. Простите за неточность.