Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

bool to QByteArray implicit conversion curiosity?



  • Today, while fixing standards conformance issues using VS2019's /permissive- option and Qt 5.15.1, I 'discovered' the following (when compiling without the /permissive- flag):

    The initialization

    QByteArray baTrue = true;
    

    gives the compiler error

    error C2440: 'initializing': cannot convert from 'bool' to 'QByteArray'
    message : No constructor could take the source type, or constructor overload resolution was ambiguous
    

    However, the following seems to pass:

    QByteArray baFalse = false;
    

    with the following Google Test assertions holding

        ASSERT_TRUE(baFalse.isEmpty());
        ASSERT_TRUE(baFalse.isNull());
        ASSERT_NE(baFalse, QByteArray("0"));
    

    What the hell is happening here???



  • @Bart_Vandewoestyne
    In my gcc/clang, the statement QByteArray baFalse = false; generates the same "no viable conversion" error as QByteArray baTrue = true; does.

    I can't help what your MSVC might or might not do about this. At a guess it treats it as a match against the QByteArray::QByteArray(const char *data, int size = -1) overload:

    Constructs a byte array containing the first size bytes of array data.

    If data is 0, a null byte array is constructed.

    I am guessing that false is getting coerced to C++ 0/nullptr in your compiler?



  • @JonB said in bool to QByteArray implicit conversion curiosity?:

    I am guessing that false is getting coerced to C++ 0/nullptr in your compiler?

    Yep, it sure looks like that. However, at https://stackoverflow.com/questions/37214420/conversion-of-false-to-object-via-const-char-constructor I find that in C++14, also the false case should not pass (which is probably why you also got an error for false with your version of gcc/clang). However, for as far as I can see, I am using C++14 (which is the default in VS2019 apparently):

    b7200e85-f4b1-4f24-b975-bc1497c4325a-image.png

    Not completely sure why my false case then passes to be honest...


  • Lifetime Qt Champion

    Maybe a compiler bug/quirk. You can try it out with a simple class with this ctor

    class Foo {
      Foo(const char *);
    }
    


  • @Christian-Ehrlicher said in bool to QByteArray implicit conversion curiosity?:

    Maybe a compiler bug/quirk. You can try it out with a simple class with this ctor

    class Foo {
      Foo(const char *);
    }
    

    OK, so here's the program I used to test:

    struct Foo {
      Foo(const char*) {}
    };
    
    int main()
    {
        Foo f = false;
    }
    

    First, I test with the following g++ version under Cygwin:

    $ g++ --version | head -1
    g++.exe (x86_64-posix-seh, Built by strawberryperl.com project) 8.3.0
    

    C++98 compilation output only gives a warning, but compiles:

    $ g++ -std=c++98 bool_to_type_implicit_conversion.cpp
    bool_to_type_implicit_conversion.cpp: In function 'int main()':
    bool_to_type_implicit_conversion.cpp:7:13: warning: converting 'false' to pointer type for argument 1 of 'Foo::Foo(const char*)' [-Wconversion-null]
         Foo f = false;
                 ^~~~~
    

    C++11 and C++14 compilation output gives an error:

    $ g++ -std=c++11 bool_to_type_implicit_conversion.cpp
    bool_to_type_implicit_conversion.cpp: In function 'int main()':
    bool_to_type_implicit_conversion.cpp:7:13: error: conversion from 'bool' to non-scalar type 'Foo' requested
         Foo f = false;
                 ^~~~~
    
    $ g++ -std=c++14 bool_to_type_implicit_conversion.cpp
    bool_to_type_implicit_conversion.cpp: In function 'int main()':
    bool_to_type_implicit_conversion.cpp:7:13: error: conversion from 'bool' to non-scalar type 'Foo' requested
         Foo f = false;
                 ^~~~~
    

    Using the Visual Studio 2019 compiler in C++14 and C++17 does not give an error:

    D:\GIT\Cpp\tests>cl /std:c++14 bool_to_type_implicit_conversion.cpp
    Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29335 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    bool_to_type_implicit_conversion.cpp
    Microsoft (R) Incremental Linker Version 14.28.29335.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:bool_to_type_implicit_conversion.exe
    bool_to_type_implicit_conversion.obj
    
    D:\GIT\Cpp\tests>cl /std:c++17 bool_to_type_implicit_conversion.cpp
    Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29335 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    bool_to_type_implicit_conversion.cpp
    Microsoft (R) Incremental Linker Version 14.28.29335.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:bool_to_type_implicit_conversion.exe
    bool_to_type_implicit_conversion.obj
    

    Using the Visual Studio 2019 compiler in 'c++latest' mode does give an error:

    D:\GIT\Cpp\tests>cl /std:c++latest bool_to_type_implicit_conversion.cpp
    Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29335 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /std:c++latest is provided as a preview of language features from the latest C++
    working draft, and we're eager to hear about bugs and suggestions for improvements.
    However, note that these features are provided as-is without support, and subject
    to changes or removal as the working draft evolves. See
    https://go.microsoft.com/fwlink/?linkid=2045807 for details.
    
    bool_to_type_implicit_conversion.cpp
    bool_to_type_implicit_conversion.cpp(7): error C2440: 'initializing': cannot convert from 'bool' to 'Foo'
    bool_to_type_implicit_conversion.cpp(7): note: No constructor could take the source type, or constructor overload resolution was ambiguous
    

    I'm not sure what the correct behavior for C++11, C++14, C++17 or 'c++latest' should be, but clearly there is a difference in behavior between g++ and the cl compiler for C++14...


  • Lifetime Qt Champion

    I would say MSVC is wrong. nullptr and false are two different values which should not be castable to each other.



  • @Bart_Vandewoestyne , @Christian-Ehrlicher
    The specifically MSVC issue seems to be https://developercommunity.visualstudio.com/content/problem/47568/false-to-pointer-implicit-conversion.html

    with Mr Microsoft seemingly only addressing this in August 2019 (my bold)

    Hi all, thank you for submitting the feedback. This wording was changed in a Defect Report against C++11, known as CWG 903. Since this is a breaking change, we've implemented it under our conformance mode /permissive-. It will be available in a future release of VS 2019--most likely VS 2019 16.4 Preview 1. You'll get another post on this thread when the fix is available.

    Then back in https://docs.microsoft.com/en-us/cpp/overview/cpp-conformance-improvements?view=msvc-160 mentioned earlier:

    Implicit conversion of integral constant expressions to null pointer

    The MSVC compiler now implements CWG Issue 903 in conformance mode (/permissive-). This rule disallows implicit conversion of integral constant expressions (except for the integer literal '0') to null pointer constants. The following example produces C2440 in conformance mode:

    int* f(bool* p) {
        p = false; // error C2440: '=': cannot convert from 'bool' to 'bool *'
        p = 0; // OK
        return false; // error C2440: 'return': cannot convert from 'bool' to 'int *'
    }
    

    To fix the error, use nullptr instead of false. A literal 0 is still allowed:

    int* f(bool* p) {
        p = nullptr; // OK
        p = 0; // OK
        return nullptr; // OK
    }
    

Log in to reply