Type of ternary operator integer expression when used in aggregate struct initialisation

Viewed 106

I've run into an interesting warning (with GCC and clang -Wnarrowing at least, haven't tested other compilers), when aggregate initialising a struct using a ternary operator expression (see below code). I don't understand why the type of the expression is apparently considered int in the aggregate initialisation case, but is silently coerced to be a size_t in the others. If C++23 size_t literals were a thing this would not be a problem obviously, as you'd just use the correct literal type. I'm just curious what's actually going on here, if anyone knows?

#include <cstddef>

int main()
{
    struct S { size_t m; };

    S s1 = {0}; // No warning

    bool b = true;
    S s2 = {b ? 1 : 0}; // warning: narrowing conversion of '(b ? 1 : 0)' from 'int' to 'size_t'
    //S s2 = {b ? 1u : 0u}; // No warning

    size_t s3 = b ? 1 : 0; // No warning

    return s1.m || s2.m || s3;
}
1 Answers

The type of b ? 1 : 0 is certainly int.

Brace-initialization (including aggregate initialization) is not allowed to perform narrowing conversions, such as a conversion from a signed type to an unsigned type. This is a narrowing conversion because some values in the source type (i.e., negative numbers) cannot be represented in the destination type. When a narrowing conversion occurs in a non-brace context, it is allowed.

GCC treats the disallowed narrowing conversions as a warning instead of an error, but technically, your code is ill-formed.

Related