Здравствуйте, Masterkent, Вы писали:
M>По правилам C++03 нестатический data member нельзя использовать в таком контексте — см. http://rsdn.ru/forum/cpp/4359858.1.aspx
Хм, а логика? Что они в этом усмотрели крамольного?
M>IMHO, проще всего ввести typedef:
Можно, у меня идея была несколько другая — контролировать посредством макроса Assume соответствие размеров массивов, определенных в разных классах, размерам глобальных массивов, с которыми они взаимодействуют. Непосредственно через размер оно получается надежнее, чем через параметры.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>При попытке использовать внутри описания класса sizeof от члена класса, например, вот так:
ЕМ>
ЕМ>class xxx {
ЕМ> int aaa;
ЕМ> int bbb [sizeof (aaa)];
ЕМ>};
ЕМ>
ЕМ>компилятор MS VC 14.00.50727.762 (от VS 2005) считает это ошибкой:
ЕМ>
ЕМ>error C2327: 'xxx::aaa' : is not a type name, static, or enumerator
ЕМ>error C2065: 'aaa' : undeclared identifier
ЕМ>Отчего компилятор не видит уже определенного члена класса, и можно ли это как-то обойти?
Не смотря на то, выражения, переданные оператору sizeof в качестве аргументов, не вычисляются, выражение sizeof(aaa) формально считается использованием не статического члена класса, отсюда и ошибка.
Обойти, помимо предложенного варианта с typedef, можно с использованием указателя на член:
class xxx {
int aaa;
int bbb [sizeof(((xxx*)0)->*(&xxx::aaa))];
};
Но это извращение, ИМХО.
--
Re[2]: sizeof от члена класса внутри описания класса
Здравствуйте, rg45, Вы писали:
R>Не смотря на то, выражения, переданные оператору sizeof в качестве аргументов, не вычисляются, выражение sizeof(aaa) формально считается использованием не статического члена класса, отсюда и ошибка.
R>Обойти, помимо предложенного варианта с typedef, можно с использованием указателя на член: R>...
Если эту задачу приходится решать часто, можно обзавестись специальным макросом, попутно избавиться от режущего глаз использования нулевого указателя:
template<typename T, typename ClassT>
char (&member_size_aux(T ClassT::*))[sizeof(T)];
#define member_size(pointer_to_member) sizeof(member_size_aux(pointer_to_member))
class xxx {
int aaa;
int bbb [member_size(&xxx::aaa)];
};
--
Re[3]: sizeof от члена класса внутри описания класса
rg45:
R>Обойти, помимо предложенного варианта с typedef, можно с использованием указателя на член: R>
R>class xxx {
R> int aaa;
R> int bbb [sizeof(((xxx*)0)->*(&xxx::aaa))];
R>};
R>
R>Но это извращение, ИМХО.
Это некорректное решение, и компилятор студии отказывается его компилить.
C++03 — 5.5/3:
The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” (where T is a completely-defined class type) to its first operand, which shall be of type “pointer to T” or “pointer to a class of which T is an unambiguous and accessible base class.”
В данном случае xxx — никакой не completely-defined class type.
Re[3]: sizeof от члена класса внутри описания класса
rg45:
R>Если эту задачу приходится решать часто, можно обзавестись специальным макросом, попутно избавиться от режущего глаз использования нулевого указателя:
R>
Здравствуйте, Шахтер, Вы писали:
Ш>А он не определён. В этой точке xxx не полный тип.
xxx — не полный, но aaa-то — полный. Как он может измениться впоследствии? У этого ограничения есть какой-то практический смысл, или просто кому-то захотелось?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: sizeof от члена класса внутри описания класса
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Шахтер, Вы писали:
Ш>>А он не определён. В этой точке xxx не полный тип.
ЕМ>xxx — не полный, но aaa-то — полный. Как он может измениться впоследствии? У этого ограничения есть какой-то практический смысл, или просто кому-то захотелось?
А что такое aaa? Это член xxx, который неполный тип, т.е. его мемберы не видны. Символ aaa должен быть связан с чем-то.
Здравствуйте, Masterkent, Вы писали:
Ш>>А что такое aaa? Это член xxx, который неполный тип, т.е. его мемберы не видны.
M>С чего бы это вдруг? Member-ам, объявляемым позже, ничто не мешает видеть member-ы, объявленные раньше.
На самом деле все еще интереснее — вот такой класс компилируется прекрасно:
class xxx {
void a (void) { b (); }
void b (void) { }
};
Так что отказ в обработке sizeof со ссылкой на "неполноту" выглядит чистой воды произволом.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: sizeof от члена класса внутри описания класса
Евгений Музыченко:
ЕМ>На самом деле все еще интереснее — вот такой класс компилируется прекрасно:
ЕМ>
ЕМ>class xxx {
ЕМ> void a (void) { b (); }
ЕМ> void b (void) { }
ЕМ>};
ЕМ>
Внутри тела функции, определённой внутри определения класса, данный класс считается completely-defined (см. 9.2/2) и все его именованные member-ы (если они не скрыты чем-либо) могут быть легко найдены при unqualified name lookup (см. 3.4.1/8/2).
Re[7]: sizeof от члена класса внутри описания класса
Здравствуйте, Masterkent, Вы писали:
M>Внутри тела функции, определённой внутри определения класса, данный класс считается completely-defined (см. 9.2/2) и все его именованные member-ы (если они не скрыты чем-либо) могут быть легко найдены при unqualified name lookup (см. 3.4.1/8/2).
Так весь вопрос в том, почему в одном случае оно "считается", а в другом — "не считается". Есть в этом какая-то здравая логика, или чистый волюнтаризм писателей стандарта.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: sizeof от члена класса внутри описания класса
Евгений Музыченко:
M>>Внутри тела функции, определённой внутри определения класса, данный класс считается completely-defined (см. 9.2/2) и все его именованные member-ы (если они не скрыты чем-либо) могут быть легко найдены при unqualified name lookup (см. 3.4.1/8/2).
ЕМ>Так весь вопрос в том, почему в одном случае оно "считается", а в другом — "не считается". Есть в этом какая-то здравая логика, или чистый волюнтаризм писателей стандарта.
С последним примером как раз всё просто: полный разбор тела функции можно осуществить в последнюю очередь, т.к. всё, что там находится, не видно извне. Вот предположим, что есть у нас такой класс:
Очевидно, тут имеют место циклические зависимости, и компилятору нужно как-то распознать такой код как некорректный. Если запретить применять sizeof к incomplete типам и если в данной ситуации искать только ранее объявленные идентификаторы, то такое распознание реализуется довольно просто. Теперь рассмотрим другой пример:
struct Y
{
void f() { value = 0; }
char value;
};
От содержимого тела функции ничего извне не зависит. Соответственно, разбирать его до member-ов, объявленных позже, нет никакого резона. В то же время возможность в теле функции ссылаться на такие member-ы не является лишней. Вот и ввели отдельные правила. Реализуется отложенный разбор опять же несложно.
При проектировании constexpr функций для C++0x комитет по стандартизации почему-то забыл о таких важных вещах. Одна из существенных особенностей constexpr функции заключается в том, что её начинка может влиять на смысл внешнего по отношению к ней кода.
struct Z
{
static constexpr int f() { return sizeof arr; }
char arr[f()];
};
В текущей спецификации C++0x нет чёткого описания, как нужно трактовать данную циклическую зависимость. Неофициально людьми из комитета предлагается считать, что f должна рассматриваться как undefined вплоть до окончания определения Z (тогда результат её вызова в определении arr не будет константным выражением, из-за чего программа будет считаться некорректной).
Re[9]: sizeof от члена класса внутри описания класса
Ну, у Вас в примерах действительно нетривиальные зависимости, но в исходном-то сообщении ситуация совершенно тривиальная. Вот и интересно, что может помешать компилятору в процессе разбора определения класса знать размер ранее определенного простого члена?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: sizeof от члена класса внутри описания класса
Евгений Музыченко:
ЕМ>но в исходном-то сообщении ситуация совершенно тривиальная. Вот и интересно, что может помешать компилятору в процессе разбора определения класса знать размер ранее определенного простого члена?
Помешать тому коду успешно компилироваться может то, что комитет по стандартизации когда-то не предусмотрел возможность использовать подобный код. Как я уже говорил, в C++0x такой код вполне легален.