Если есть класс, в нем, допустим, несколько вложенных классов, я определяю их:
class A{
public:
class B;
class C;
};
class A::B{};
class A::C:public (??????)B{};
Где начинается область видимости A? В вижуале мне не надо писать public A::B а вот в g++ нужно. Как по стандарту?
Здравствуйте Fiend, Вы писали:
F>Если есть класс, в нем, допустим, несколько вложенных классов, я определяю их:
F>class A{
F>public:
F> class B;
F> class C;
F>};
F>class A::B{};
F>class A::C:public (??????)B{};
F>Где начинается область видимости A? В вижуале мне не надо писать public A::B а вот в g++ нужно. Как по стандарту?
Область видимости A становится доступной для поиска сразу после : так что писать полную квалификацию для B по Стандарту нет необходимости. Подробнее про точку обявления смотри 3.3.1.
Здравствуйте dupamid, Вы писали:
F>>Если есть класс, в нем, допустим, несколько вложенных классов, я определяю их: D>
F>>class A{
F>>public:
F>> class B;
F>> class C;
F>>};
F>>class A::B{};
F>>class A::C:public (??????)B{};
D>
F>>Где начинается область видимости A? В вижуале мне не надо писать public A::B а вот в g++ нужно. Как по стандарту?
D>Область видимости A становится доступной для поиска сразу после : так что писать полную квалификацию для B по Стандарту нет необходимости. Подробнее про точку обявления смотри 3.3.1.
Судя по всему, стандарт не вполне точен в отношении правил поиска имен, использованных в списке наследования. По крайней мере, ничего лучше 3.3.6/1 мне найти не удалось, и никакой уверенности, что этот пункт уточняет правила поиска имен в данном случае у меня нет, а точки объявления здесь совсем ни при чем.
3.3.6/1
5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and, for constructor functions (12.1), the ctor-initializer (12.6.2)) and any portion of the declarator part of such definitions which follows the identifier, including a parameter-declaration-clause and any default arguments (8.3.6).
По словам Bo-Staffan Lankinen, этот вопрос должен обсуждаться на следующем собрании комитета.
<< J 1.0 alpha 4 >>
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте Павел Кузнецов, Вы писали:
ПК>Судя по всему, стандарт не вполне точен в отношении правил поиска имен, использованных в списке наследования. По крайней мере, ничего лучше 3.3.6/1 мне найти не удалось, и никакой уверенности, что этот пункт уточняет правила поиска имен в данном случае у меня нет, а точки объявления здесь совсем ни при чем. ПК> ПК>3.3.6/1 ПК>5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and, for constructor functions (12.1), the ctor-initializer (12.6.2)) and any portion of the declarator part of such definitions which follows the identifier, including a parameter-declaration-clause and any default arguments (8.3.6).
ПК>По словам Bo-Staffan Lankinen, этот вопрос должен обсуждаться на следующем собрании комитета.
В общем, по-моему, все достаточно ясно 3.3.1\4:
After the point of declaration of a class member, the member name can be looked up in the scope of its class.
Из пункта 3.3.1\5 следует, что точка объявление находится после имени класса, т.е. даже перед «:» (хотя там ничего находиться не может) так что искать внутри объемлющего класса надо. Если вопрос будет поднят в комитете, то за результат можно не беспокоиться, так как дух Стандарта говорит, что искать надо.
Здравствуйте dupamid, Вы писали:
ПК>>Судя по всему, стандарт не вполне точен в отношении правил поиска имен, использованных в списке наследования. По крайней мере, ничего лучше 3.3.6/1 мне найти не удалось, и никакой уверенности, что этот пункт уточняет правила поиска имен в данном случае у меня нет, а точки объявления здесь совсем ни при чем.
ПК>>По словам Bo-Staffan Lankinen, этот вопрос должен обсуждаться на следующем собрании комитета.
D>В общем, по-моему, все достаточно ясно 3.3.1\4: D>After the point of declaration of a class member, the member name can be looked up in the scope of its class.
Это говорит совсем о другом: само объявленное имя может быть найдено при поиске имен в области видимости класса. Это совсем не говорит о том, что при определении вложенного класса вне тела содержащего, поиск имен из списка базовых классов должен осуществляться в области видимости содержащего класса. Более того, список базовых классов в определении класса является частью определения самого класса, а не его членов, поэтому, например, список базовых классов вложенного класса может содержать закрытые имена содержащего класса.
D>Из пункта 3.3.1\5 следует, что точка объявление находится после имени класса, т.е. даже перед «:»
Снова-таки, это никак не говорит, в какой области видимости должен осуществляться поиск имен из списка базовых классов. А точка объявления вложенного класса находится еще раньше — там, где он был объявлен внутри содержащего класса.
D>(хотя там ничего находиться не может)
Может, например:
class Outer
{
public:
template<class T> class Inner;
class Other;
};
class Outer::Inner<Other> : Other { }; // это не компилируется
Хотя, все доступные мне компиляторы, компилирующие пример, приведенный Fiend, не компилируют этот (Borland C++ Compiler, Intel C++ Compiler, Gcc, VC++, Comeau C++).
D>Если вопрос будет поднят в комитете, то за результат можно не беспокоиться, так как дух Стандарта говорит, что искать надо.
Вопрос звучал так: "Как по стандарту?" Пока что точного ответа я найти не могу, т.к. согласно 3.3.6/1 должен был бы компилироваться и приведенный пример. А "дух стандарта" — понятие неконкретное и спецификацией не является.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
ПК>class Outer
ПК>{
ПК>public:
ПК> template<class T> class Inner;
ПК> class Other;
ПК>};
ПК>class Outer::Inner<Other> : Other { }; // это не компилируется
ПК>Хотя, все доступные мне компиляторы, компилирующие пример, приведенный Fiend, не компилируют этот (Borland C++ Compiler, Intel C++ Compiler, Gcc, VC++, Comeau C++).
Это совершенно неверный пример!!! Как Вы такое можете писать
class Outer
{
public:
template<class T> class Inner;
class Other {}; // неполный тип, наследоваться от него нельзя, нужно добавить {}
};
template<> // нужно добавить template<>class Outer::Inner<Outer::Other> : Other { }; // это не компилируется
Так будет компилироваться! Часть находящаяся в <> является частью объявления класса, так что правило, о котором я говорю начинает действовать после >.
<...>
ПК>>Хотя, все доступные мне компиляторы, компилирующие пример, приведенный Fiend, не компилируют этот (Borland C++ Compiler, Intel C++ Compiler, Gcc, VC++, Comeau C++).
D>Это совершенно неверный пример!!! Как Вы такое можете писать
Естественно то, что выше писал для иллюстрации. Проверялось следующее:
D>
class Outer
{
public:
template<class T> class Inner;
class Other;
};
template<> // нужно добавить template<>class Outer::Inner<Other> { }; // это не компилируется
D>
D>class Outer
D>{
D>public:
D> template<class T> class Inner;
D> class Other {}; // неполный тип, наследоваться от него нельзя, нужно добавить {}
D>};
D>template<> // нужно добавить template<>
D>class Outer::Inner<Outer::Other> : Other { }; // это не компилируется
D>
D>Так будет компилироваться!
Конечно.
D>Часть находящаяся в <> является частью объявления класса, так что правило, о котором я говорю начинает действовать после >.
Какое правило? Где оно в стандарте? То, что ты написал о точках объявления сюда совершенно не лепится.
<< J 1.0 alpha 4 >>
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте Павел Кузнецов, Вы писали:
ПК>Естественно то, что выше писал для иллюстрации.
Павел, если Вы что-то пишите и говорите, что оно нигде не компилируется, потрудитесь сделать его компилируемым в принципе. Так как Вы написали оно действительно нигде компилироваться просто не должно!
ПК>Какое правило? Где оно в стандарте? То, что ты написал о точках объявления сюда совершенно не лепится.
. Там все поясняется, извиняюсь, что был не совсем точен говоря имя класса, я допустил небольшую вольность речи.
Мне очень жаль, если я Вас чем-то обидел, честное слово не со зла. Мне очень интересно и познавательно с Вами спорить, так что давайте не опускаться до выяснения личных отношений.
Здравствуйте dupamid, Вы писали:
ПК>>Естественно то, что выше писал для иллюстрации.
D>Павел, если Вы что-то пишите и говорите, что оно нигде не компилируется, потрудитесь сделать его компилируемым в принципе. Так как Вы написали оно действительно нигде компилироваться просто не должно!
Stand corrected. Буду стараться, но, к сожалению (?), никто не застрахован даже от тривиальных ошибок.
ПК>>Какое правило? Где оно в стандарте? То, что ты написал о точках объявления сюда совершенно не лепится.
D>Прочтите мое сообщение http://www.rsdn.ru/forum/Message.aspx?mid=99808&only=1
. Там все поясняется, извиняюсь, что был не совсем точен говоря имя класса, я допустил небольшую вольность речи.
То, что ты там написал никоим образом не проясняет ситуацию в целом. Точки объявления здесь просто ни при чем, как я уже подробно расписал в предыдущем сообщении
.
D>Мне очень жаль, если я Вас чем-то обидел, честное слово не со зла.
Ничуть. С чего ты взял? Кстати, что это ты все время со мной на Вы? Не думаю, что я значительно старше...
D>давайте не опускаться до выяснения личных отношений.
Это где?
<< J 1.0 alpha 4 >>
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
После небольшой медитации выяснилось, что вопрос действительно очень интересный! Так что я должен опять тебя поблагодарить, спасибо. Насчет «ты» и «Вы», это результат академического образования, писать «мы» все то «я» (с этим я уже поборолся) и «Вы» вместо «ты»; возраст тут ни причем, я действительно не думаю, что разница в возрасте у нас велика. Постараюсь в дальнейшем писать «ты», может быть я бы больше использовал «ты», если бы не видел как отчитали Андрея Тарасевича за это в одном из топиков. Насчет «выяснения отношения» это, видимо, был пустой наезд, извиняюсь, погорячился из-за примера содержащего другие ошибки, которые выявляются до той ошибки, на которую сделан пример.
Теперь по существу вопроса. Все даже еще более запутано, чем я мог предположить, вот примеры. В начале с твоим примером, но без остальных ошибок:
[ccode]
struct A
{
template<class T>
struct B;
struct C;
};
template<>
struct A::B<C>
{
};
[\ccode]
Если следовать букве Стандарта 3.3.6\1
5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and, for constructor functions (12.1), the ctor-initializer (12.6.2)) and any portion of the declarator part of such definitions which follows the identifier, including a parameter-declaration-clause and any default arguments (8.3.6).
То приводимый пример должен компилироваться, но компилятор находясь внутри <> еще не может знать, что мы собираемся объявлять член класса, так как может быть, например:
[ccode]
template<>
struct A::B<C> f();
[\ccode]
Более того имя C может быть известно в глобальной области и означать что-то совсем другое, так что в данном случае открывать для поиска класс А до точки объявления нельзя. Так что компилятор по другому работать в общем-то и не может.
[ccode]
struct A
{
enum { size = 10 };
static int a[];
};
int A::a[size];
[\ccode]
Приличные компиляторы это компилируют без ошибок, и моя теория о точках объявления не подтверждается. Видимо этот пример соответствует Стандарту.
[ccode]
struct A
{
static int C;
static int a;
};
struct C {};
int A::a(C);
[\ccode]
Это тоже компилируется без ошибок, что является, по-видимому, правильно. Но вот такой пример уже вызывает проблемы:
[ccode]
struct A
{
typedef int C;
static int a;
};
struct C {};
int A::a(C());
[\ccode]
MSVC его компилирует без ошибок, а вот Borland C++ 5.5 видит ошибку, что член а переобъявляется как функция, с ошибкой согласны и более продвинутые компиляторы. Хотя я считаю, что этот пример не должен отличается от предыдущего и поведение компиляторов должно быть одинаковым. С другой стороны я понимаю по чему это сложный пример – компилятор должен в данном случае разрешить синтаксическую неоднозначность, по общим правилам она должна решаться в пользу функции, но здесь видно что функцией это быть не может уже не может, так как поиск имени четко говорит что это объект.
Как говориться чем дальше в лес тем толще партизаны:
[ccode]
namespace N
{
struct A;
void f(A&);
}
void N::f(A&)
{
}
[\ccode]
Все известные мне компиляторы это кушают, хотя в Стандарте я не нашел места где бы это явно разрешалось. По духу С++ это должно быть можно делать, так как существует явная аналогия с классами, но в Стандарте я этого не нашел. Если приведешь ссылку буду благодарен, в пункте 3.3.5, в котором это должно быть по аналогии с классами, ничего такого нет.
Интересно, что такой пример тоже работает:
[ccode]
namespace N
{
enum { size = 10 };
extern int a[];
}
Здравствуйте dupamid, Вы писали:
D>После небольшой медитации выяснилось, что вопрос действительно очень интересный!
Ну, а то :-) Как уже сообщалось, Bo-Staffan Lankinen попросил разработчиков компилятора, которым он пользуется, поднять этот вопрос на ближайшем собрании комитета и обещал сообщить о результатах. Хотя, вполне возможно, что все есть, просто мы все читать не очень умеем. Не зря же name lookup считается одной из самых запутанных частей текущего стандарта :-)
D>Насчет «ты» и «Вы»
Never mind. Просто мне показалось, что твое ощущение, что я "обиделся" обусловлено именно тем, что я допускаю себе некоторые вольности в обращениях, вот и попробовал оправдаться :-) Т.к. ты уже второй, кто это замечает, буду работать над собой :-)
D>Теперь по существу вопроса. Все даже еще более запутано, чем я мог предположить, вот примеры. В начале с твоим примером, но без остальных ошибок:
<...> D>Если следовать букве Стандарта 3.3.6\1 <...> То приводимый пример должен компилироваться,
Вот именно об этом я и говорил, может быть, не вполне ясно (но см. ниже).
D>но компилятор находясь внутри <> еще не может знать, что мы собираемся объявлять член класса <...>
(Определять, хоть это и не сильно важно в данном случае). Ну, почему пример не компилируется, более чем понятно. Вопрос как раз был в формулировке в стандарте, но, кажется, я нашел соответствующее место:
3.4.3.1 Class members 1 If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-name-specifier is looked up in the scope of the class (10.2), except for the cases listed below. <...>
— the template-arguments of a template-id are looked up in the context in which the entire postfix-expression occurs.
D>
D>struct A
D>{
D> enum { size = 10 };
D> static int a[];
D>};
D>int A::a[size];[\ccode]
D>Приличные компиляторы это компилируют без ошибок, и моя теория о точках объявления не подтверждается.
Точки объявления здесь определенно ни при чем, т.к. для членов класса точки объявления находятся внутри содержащего класса.
D>Видимо этот пример соответствует Стандарту.
Похоже на то.
D>[ccode]
D>struct A
D>{
D> static int C;
D> static int a;
D>};
D>struct C {};
D>int A::a(C);[\ccode]
D>Это тоже компилируется без ошибок, что является, по-видимому, правильно.
Согласен.
D>Но вот такой пример уже вызывает проблемы:
D>[ccode]
D>struct A
D>{
D> typedef int C;
D> static int a;
D>};
D>struct C {}; // ПК: в принципе, это здесь лишнее
D>int A::a(C());[\ccode]
D>MSVC его компилирует без ошибок, а вот Borland C++ 5.5 видит ошибку, что член а переобъявляется как функция, с ошибкой согласны и более продвинутые компиляторы.
Это ошибка MSVC++, родственная той, которая позволяет ему компилировать:
[ccode]
int main()
{
int a (int());
return a;
}
D>Хотя я считаю, что этот пример не должен отличается от предыдущего и поведение компиляторов должно быть одинаковым. С другой стороны я понимаю по чему это сложный пример – компилятор должен в данном случае разрешить синтаксическую неоднозначность, по общим правилам она должна решаться в пользу функции, но здесь видно что функцией это быть не может уже не может, так как поиск имени четко говорит что это объект.
Поиск имени `a' в данном случае не осуществляется до тех пор, пока не будет определено, что за конструкцию написал программист. А в процессе определения оказывается, что программист написал определение функции, после чего выясняется, что в классе объявлен объект с тем же именем, то бишь, в каком-то из двух мест ошибка, о чем честно и говорит bcc32.
D>[ccode] D>namespace N D>{ D> struct A; D> void f(A&); D>}
D>void N::f(A&) D>{ D>}[\ccode] D>Все известные мне компиляторы это кушают, хотя в Стандарте я не нашел места где бы это явно разрешалось.
Насчет определения функции вне области видимости:
7.3.1.2 Namespace member definitions: 2 Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace. [Example: <...>
Насчет использования имени A без квалификации:
3.4.1 Unqualified name lookup 6 A name used in the definition of a function 26) that is a member of namespace N (where, only for the purpose of exposition, N could represent the global scope) shall be declared before its use in the block in which it is used or in one of its enclosing blocks (6.3) or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N’s enclosing namespaces.
26) This refers to unqualified names following the function declarator; such a name may be used as a type or as a default argument name in the parameter-declaration-clause, or may be used in the function body.
Кстати, следующий же абзац (7) содержит дополнительные указания насчет имен, использованных в списке базовых классов.
D>Интересно, что такой пример тоже работает: D>[ccode] D>namespace N D>{ D> enum { size = 10 }; D> extern int a[]; D>}
D>int N::a[size]; D>[\ccode]
"— Видишь сурка? — Нет. — А он есть." :-)
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте Павел Кузнецов.
ПК>Never mind. Просто мне показалось, что твое ощущение, что я "обиделся" обусловлено именно тем, что я допускаю себе некоторые вольности в обращениях, вот и попробовал оправдаться Т.к. ты уже второй, кто это замечает, буду работать над собой
Работа на собой никогда лишней не бывает , но как говориться "кто сам без греха..."
Пункты 3.4.3\3 и 3.4.3.1\1 я уже тоже нашел и по-моему тоже все там четко и ясно. Стандарт вещь такая, что найти в ней что-то бывает очень трудно, так как оно может находиться в самых неожиданных местах.