sizeof от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.08.11 07:08
Оценка:
При попытке использовать внутри описания класса 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


Отчего компилятор не видит уже определенного члена класса, и можно ли это как-то обойти?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: sizeof от члена класса внутри описания класса
От: panter_dsd Россия panter-dsd.narod.ru
Дата: 08.08.11 07:15
Оценка:
clang++ выдает вот такое:
clang\++ ./main.cpp
./main.cpp:6:20: error: invalid use of nonstatic data member 'aaa'
  int bbb [sizeof (aaa)];
                   ^~~
С уважением.
Пантер.
Re[2]: sizeof от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.08.11 07:27
Оценка:
Здравствуйте, panter_dsd, Вы писали:

_>clang++ выдает вот такое:

_>
_>clang\++ ./main.cpp
_>./main.cpp:6:20: error: invalid use of nonstatic data member 'aaa'
_>  int bbb [sizeof (aaa)];
_>                   ^~~
_>


Тоже странно. Что им не нравится-то?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: sizeof от члена класса внутри описания класса
От: Masterkent  
Дата: 08.08.11 07:45
Оценка:
Евгений Музыченко:

ЕМ>Отчего компилятор не видит уже определенного члена класса


По правилам C++03 нестатический data member нельзя использовать в таком контексте — см. http://rsdn.ru/forum/cpp/4359858.1.aspx
Автор: Masterkent
Дата: 28.07.11

C++0x такую запись разрешает.

ЕМ>и можно ли это как-то обойти?


IMHO, проще всего ввести typedef:

class xxx {
  typedef int A;
  A a;
  int b [sizeof (A)];    
};
Re[2]: sizeof от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.08.11 08:02
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>По правилам C++03 нестатический data member нельзя использовать в таком контексте — см. http://rsdn.ru/forum/cpp/4359858.1.aspx
Автор: Masterkent
Дата: 28.07.11


Хм, а логика? Что они в этом усмотрели крамольного?

M>IMHO, проще всего ввести typedef:


Можно, у меня идея была несколько другая — контролировать посредством макроса Assume соответствие размеров массивов, определенных в разных классах, размерам глобальных массивов, с которыми они взаимодействуют. Непосредственно через размер оно получается надежнее, чем через параметры.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: sizeof от члена класса внутри описания класса
От: rg45 СССР  
Дата: 08.08.11 08:59
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>При попытке использовать внутри описания класса 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 СССР  
Дата: 08.08.11 09:17
Оценка: 13 (2)
Здравствуйте, 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 от члена класса внутри описания класса
От: panter_dsd Россия panter-dsd.narod.ru
Дата: 08.08.11 10:34
Оценка:
Проще уж тогда через typedef.
С уважением.
Пантер.
Re[2]: sizeof от члена класса внутри описания класса
От: Masterkent  
Дата: 08.08.11 10:40
Оценка: 5 (1)
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 от члена класса внутри описания класса
От: Masterkent  
Дата: 08.08.11 10:43
Оценка: 5 (1)
rg45:

R>Если эту задачу приходится решать часто, можно обзавестись специальным макросом, попутно избавиться от режущего глаз использования нулевого указателя:


R>
R>template<typename T, typename ClassT>
R>char (&member_size_aux(T ClassT::*))[sizeof(T)];

R>#define member_size(pointer_to_member) sizeof(member_size_aux(pointer_to_member))

R>class xxx {

R>  int aaa;

R>  int bbb [member_size(&xxx::aaa)];
R>};
R>

Данный вариант я тоже как-то приводил: http://rsdn.ru/forum/cpp/3974318.1.aspx
Автор: Masterkent
Дата: 27.09.10

Однако автору топика это вряд ли поможет, т.к VC++8.0, VC++9.0 и VC++10.0 отказываются это компилить.
Re: sizeof от члена класса внутри описания класса
От: Шахтер Интернет  
Дата: 08.08.11 17:20
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>При попытке использовать внутри описания класса 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


ЕМ>Отчего компилятор не видит уже определенного члена класса, и можно ли это как-то обойти?


А он не определён. В этой точке xxx не полный тип.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: sizeof от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.08.11 17:36
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>А он не определён. В этой точке xxx не полный тип.


xxx — не полный, но aaa-то — полный. Как он может измениться впоследствии? У этого ограничения есть какой-то практический смысл, или просто кому-то захотелось?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: sizeof от члена класса внутри описания класса
От: Шахтер Интернет  
Дата: 08.08.11 18:10
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Шахтер, Вы писали:


Ш>>А он не определён. В этой точке xxx не полный тип.


ЕМ>xxx — не полный, но aaa-то — полный. Как он может измениться впоследствии? У этого ограничения есть какой-то практический смысл, или просто кому-то захотелось?


А что такое aaa? Это член xxx, который неполный тип, т.е. его мемберы не видны. Символ aaa должен быть связан с чем-то.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: sizeof от члена класса внутри описания класса
От: Masterkent  
Дата: 08.08.11 19:05
Оценка:
Шахтер:

Ш>А что такое aaa? Это член xxx, который неполный тип, т.е. его мемберы не видны.


С чего бы это вдруг? Member-ам, объявляемым позже, ничто не мешает видеть member-ы, объявленные раньше.
Re[5]: sizeof от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.08.11 03:23
Оценка: +1
Здравствуйте, 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 от члена класса внутри описания класса
От: Masterkent  
Дата: 09.08.11 05:19
Оценка:
Евгений Музыченко:

ЕМ>На самом деле все еще интереснее — вот такой класс компилируется прекрасно:


ЕМ>
ЕМ>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 от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.08.11 05:43
Оценка:
Здравствуйте, 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 от члена класса внутри описания класса
От: Masterkent  
Дата: 09.08.11 11:18
Оценка: 3 (1)
Евгений Музыченко:

M>>Внутри тела функции, определённой внутри определения класса, данный класс считается completely-defined (см. 9.2/2) и все его именованные member-ы (если они не скрыты чем-либо) могут быть легко найдены при unqualified name lookup (см. 3.4.1/8/2).


ЕМ>Так весь вопрос в том, почему в одном случае оно "считается", а в другом — "не считается". Есть в этом какая-то здравая логика, или чистый волюнтаризм писателей стандарта.


С последним примером как раз всё просто: полный разбор тела функции можно осуществить в последнюю очередь, т.к. всё, что там находится, не видно извне. Вот предположим, что есть у нас такой класс:

struct X
{
    char a[sizeof(X)];
    static char b[sizeof(X::c)];
    static char c[sizeof(X::b)];
};

Очевидно, тут имеют место циклические зависимости, и компилятору нужно как-то распознать такой код как некорректный. Если запретить применять 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 от члена класса внутри описания класса
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.08.11 11:44
Оценка:
Здравствуйте, Masterkent, Вы писали:

Ну, у Вас в примерах действительно нетривиальные зависимости, но в исходном-то сообщении ситуация совершенно тривиальная. Вот и интересно, что может помешать компилятору в процессе разбора определения класса знать размер ранее определенного простого члена?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: sizeof от члена класса внутри описания класса
От: Masterkent  
Дата: 09.08.11 12:41
Оценка: 16 (1)
Евгений Музыченко:

ЕМ>но в исходном-то сообщении ситуация совершенно тривиальная. Вот и интересно, что может помешать компилятору в процессе разбора определения класса знать размер ранее определенного простого члена?


Помешать тому коду успешно компилироваться может то, что комитет по стандартизации когда-то не предусмотрел возможность использовать подобный код. Как я уже говорил, в C++0x такой код вполне легален.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.