8

Visual C++ 2017 and gcc 5.4 produce conversion from 'const unsigned char' to 'const float' requires a narrowing conversion warning for Line B but not for Line A in this code snippet:

#include <iostream>

int main() {
    const unsigned char p = 13;
    const float         q = p;  // Line A

    std::cout << q << '\n';

    const unsigned char c[3] = {0, 1, 255};
    const float         f[3] = {c[2], c[0], c[1]};  // Line B

    for (auto x:f)
        std::cout << x << '\n';
}

Is this warning valid? Why Line B is treated differently than Line A?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Paul Jurczak
  • 7,008
  • 3
  • 47
  • 72

1 Answers1

5

The warning is valid, from C++11 narrowing conversions are prohibited in aggregate initialization; but not applied in copy initialization (as before).

If the initializer clause is an expression, implicit conversions are allowed as per copy-initialization, except if they are narrowing (as in list-initialization) (since C++11).

Until C++11, narrowing conversions were permitted in aggregate initialization, but they are no longer allowed.

And

list-initialization limits the allowed implicit conversions by prohibiting the following:

  • conversion from an integer type to a floating-point type, except where the source is a constant expression whose value can be stored exactly in the target type

BTW: c[0], c[1] and c[2] are not constant expressions; you might declare the array as constexpr, i.e. constexpr unsigned char c[3] = {0, 1, 255};. Then exception applied and Line B would work fine too.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • But the initializer list in my example consists exclusively of `constant expression whose value can be stored exactly in the target type`! – Paul Jurczak Apr 25 '18 at 01:55
  • 1
    @PaulJurczak AFAIK `c[0]`, `c[1]` and `c[2]` are not constant expressions. – songyuanyao Apr 25 '18 at 01:58
  • 2
    @PaulJurczak See [`x[0] == 1` constant expression in C++11 when `x` is `const int[]`?](https://stackoverflow.com/q/18903113/3309790). – songyuanyao Apr 25 '18 at 02:20
  • Replacing `const` with `constexpr` removes the warning for gcc 5.4, but not for Visual C++ 2017. – Paul Jurczak Apr 25 '18 at 03:01
  • @PaulJurczak I guess it's a VS issue; it's not standard-compliant in some ways. – songyuanyao Apr 25 '18 at 03:05
  • One question still remains: prohibition of implicit conversion by language standard in this case is now clear to me, but the warning complains about `narrowing conversion`, which is not occuring here, unless it is about the general case of up to 64-bit `unsigned char` being converted into 32-bit `float`. – Paul Jurczak Apr 25 '18 at 03:45
  • @PaulJurczak Interesting question. The standard just says before the checking of whether the value can be stored in `float`, the source must be a constant expression. It's hard to tell the principle behind. – songyuanyao Apr 25 '18 at 04:00
  • 1
    @songyuanyao: Warnings do not make a compiler non-complaint. The reverse isn't true; when the Standard requires a diagnostic the compiler must emit at least a warning. – MSalters Apr 25 '18 at 07:37
  • @MSalters I meant after replacing `const` with `constexpr` VS shouldn't give warnings. – songyuanyao Apr 25 '18 at 07:39
  • @songyuanyao It shouldn't, but what MSalters is saying (AFAICS) is that this is a quality of implementation issue, not one of standard-compliance. – Arne Vogel Apr 25 '18 at 07:45
  • @ArneVogel But it's giving a (wrong) diagnostic on well-formed code; well, I can understand what you said. – songyuanyao Apr 25 '18 at 07:56
  • 2
    @songyuanyao: A compiler could give the warning for using the letter E too much, and still be compliant. The Standard only requires that the compiler produces a correct binary for well-formed code. – MSalters Apr 25 '18 at 07:59