1

In the following code,

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),
    // ...
  };
}

why does the first initializer in the initializer list of BlitData give the following error:

Non-constant-expression cannot be narrowed from type col24 (aka unsigned long) to int in initializer list

Why is the compiler trying to initialize the int member of the union with the initializer whose type is col24 instead of using it to initialize the col24 member?

The compiler suggests that I static_cast the result of MakeRGB24 to int, but this could result in an unwanted narrowing.

How can the Luminance member be correctly initialized using the result of MakeRGB24 in the initializer list?

Edit: blitdata should stay POD.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • *"Why is the compiler trying to initialize the int member of the union"* Because aggregate-initialization (which you are using in `main`) is very simplistic. The first initializer you provide initializes the first member of `BlitData`. – dyp Jul 23 '15 at 14:39
  • See http://stackoverflow.com/questions/13056366/can-i-initialize-a-union-in-a-mem-initializer . You need to declare a few constructors. – Sorin Jul 23 '15 at 14:40
  • I don't know what you're trying to achieve, but don't rely on `sizeof(unsigned long)` to have any particular value, except that it is no less than `sizeof(int)`. – Walter Jul 23 '15 at 14:45
  • @Sorin, unfortunately the struct should stay POD and the union anonymous. – Emil Laine Jul 23 '15 at 14:55
  • @zenith Which definition of POD are you referring to? C++03 or C++11? Since C++11, PODs can have user-declared constructors; and C++11's brace-initialization allows even non-aggregates to be initialized with POD-style `{..}` initialization. – dyp Jul 23 '15 at 15:06
  • @dyp The code was originally C++98/03, so the initializer worked without the error. Now were porting it to C++11 and this error came up. So I guess it can be turned to a C++11 POD while maintaining compatibility. – Emil Laine Jul 23 '15 at 15:29
  • Even in C++03, your initializer in `main` tries to initialize the `Flags` member. However, the conversion from `unsigned long` (aka `col24`) to `int` was not illegal in C++03. So switching to C++11 has uncovered some kind of bug, I suppose. – dyp Jul 23 '15 at 16:03
  • @dyp Maybe. I'll look into that. Thanks. – Emil Laine Jul 23 '15 at 20:28

1 Answers1

0

This is apparently a nonstandard gcc extension, but this could be what you're after:

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

If that's no good for you, I suspect assigning it afterwards is the only way.

Muzer
  • 774
  • 4
  • 11
  • That looks a bit like C99's *designated initializers*. However, they'd be written as `{ .Luminance = MakeRgb24(0,0,0) }` as far as I know. – dyp Jul 23 '15 at 14:50
  • C99 designated initializers are accepted by clang as an extension in C++ mode, so I'd recommend that over the GCC-specific extension. They are _not_ accepted by cmd.exe (MSVC) in C++ mode, although I believe it supports them in C mode. – celticminstrel Jul 23 '15 at 15:03
  • I was under the impression that g++ didn't support them; am I wrong here? – Muzer Jul 23 '15 at 15:07
  • @Muzer See http://coliru.stacked-crooked.com/a/e6d6e931cf0e22cd "sorry, unimplemented: non-trivial designated initializers not supported" – dyp Jul 23 '15 at 15:08