Инициализация члена союза в списке инициализаторов без сужения

В следующем коде

typedef unsigned long col24;
inline col24 MakeRGB24(int R, int G, int B) { return ...; }

struct blitdata
{
  union
  {
    int Flags, Stretch;
    col24 Luminance;
  };
  // (other members)
};

int main()
{
  blitdata BlitData =
  {
    MakeRGB24(0, 0, 0),
    // ...
  };
}

почему первый инициализатор в списке инициализаторов BlitData выдает следующую ошибку:

Неконстантное выражение не может быть сужено от типа col24 (также известного как unsigned long) до int в списке инициализаторов.

Почему компилятор пытается инициализировать элемент int элемента union с помощью инициализатора типа col24 вместо того, чтобы использовать его для инициализации элемента col24?

Компилятор предлагает мне static_cast результат от MakeRGB24 до int, но это может привести к нежелательному сужению.

Как правильно инициализировать член Luminance, используя результат MakeRGB24 в списке инициализаторов?

Изменить: blitdata следует оставить POD.


person emlai    schedule 23.07.2015    source источник
comment
Почему компилятор пытается инициализировать член объединения int Потому что агрегатная инициализация (которую вы используете в main) очень упрощена. Первый предоставленный вами инициализатор инициализирует первый элемент BlitData.   -  person dyp    schedule 23.07.2015
comment
См. stackoverflow.com/questions/13056366/ . Вам нужно объявить несколько конструкторов.   -  person Sorin    schedule 23.07.2015
comment
Я не знаю, чего вы пытаетесь достичь, но не полагайтесь на то, что sizeof(unsigned long) имеет какое-либо конкретное значение, за исключением того, что оно не меньше sizeof(int).   -  person Walter    schedule 23.07.2015
comment
@Sorin, к сожалению, структура должна оставаться POD, а объединение анонимным.   -  person emlai    schedule 23.07.2015
comment
@zenith Какое определение POD вы имеете в виду? С++ 03 или С++ 11? Начиная с C++11, POD могут иметь конструкторы, объявленные пользователем; а инициализация скобок C++11 позволяет инициализировать даже неагрегаты с помощью инициализации {..} в стиле POD.   -  person dyp    schedule 23.07.2015
comment
@dyp Код изначально был C++ 98/03, поэтому инициализатор работал без ошибок. Сейчас портировали его на С++ 11 и вылезла эта ошибка. Поэтому я думаю, что его можно превратить в POD C++11, сохранив при этом совместимость.   -  person emlai    schedule 23.07.2015
comment
Даже в C++03 ваш инициализатор в main пытается инициализировать элемент Flags. Однако преобразование из unsigned long (он же col24) в int не было недопустимым в C++03. Так что переход на С++ 11, я полагаю, обнаружил какую-то ошибку.   -  person dyp    schedule 23.07.2015
comment
@dyp Возможно. Я посмотрю на это. Спасибо.   -  person emlai    schedule 23.07.2015


Ответы (1)


Это, по-видимому, нестандартное расширение gcc, но это может быть то, что вам нужно:

blitdata BlitData =
{
    Luminance: MakeRgb24(0,0,0),
};

Если это нехорошо для вас, я подозреваю, что назначить его позже - единственный способ.

person Muzer    schedule 23.07.2015
comment
Это немного похоже на назначенные инициализаторы C99. Однако, насколько я знаю, они будут записаны как { .Luminance = MakeRgb24(0,0,0) }. - person dyp; 23.07.2015
comment
Инициализаторы, назначенные C99, принимаются clang как расширение в режиме C++, поэтому я бы рекомендовал это вместо расширения, специфичного для GCC. Они не принимаются cmd.exe (MSVC) в режиме C++, хотя я считаю, что он поддерживает их в режиме C. - person celticminstrel; 23.07.2015
comment
У меня сложилось впечатление, что g++ их не поддерживает; я ошибаюсь здесь? - person Muzer; 23.07.2015
comment
@Muzer См. coliru.stacked-crooked.com/a/e6d6e931cf0e22cd, извините, не реализовано: нетривиальные назначенные инициализаторы не поддерживаются - person dyp; 23.07.2015