1

The following code compiles fine with msvc and clang but issues a narrowing warning for gcc 12.1. I think gcc is trying to do the wrong thing: It tries to convert const char* to bool even though there exists a std::string constructor in the ref object which would arguably be more fitting. Not only that but you can try to "explicit out" the bool constructor in which case it tries to convert to int for the int constructor. If you explicit out the int constructor as well it fails completely (it doesn't even seem to look at the string constructor). Seems like a gcc bug to me as it is working fine with all other compilers.

(CompilerExplorer)

#include <variant>
#include <string>

struct ref
{
    ref(int);
    ref(bool);
    ref(std::string);
    ref(std::initializer_list<ref>);

    std::variant<std::monostate, int, bool, std::string, std::initializer_list<ref>> value_;
};

struct container : public ref
{
    using ref::ref;
};


ref::ref(int init) : value_{init} {}

ref::ref(bool init) : value_{init} {}

ref::ref(std::string init) : value_{init} {}

ref::ref(std::initializer_list<ref> init) : value_{init} {}

int main()
{
    container some_container = { 1, true, 1, { {"itemA", 2}, {"itemB", true}}};
}

gcc warning:

<source>: In function 'int main()':
<source>:30:49: warning: narrowing conversion of '(const char*)"itemA"' from 'const char*' to 'bool' [-Wnarrowing]
   30 |     container some_container = { 1, true, 1, { {"itemA", 2}, {"itemB", true}}};
      |                                                 ^~~~~~~
<source>:30:63: warning: narrowing conversion of '(const char*)"itemB"' from 'const char*' to 'bool' [-Wnarrowing]
   30 |     container some_container = { 1, true, 1, { {"itemA", 2}, {"itemB", true}}};
      |     

I just tried expliciting out the int and bool constructor with msvc and clang which fail as well. Leaves me wondering what is happening behind the curtains.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
glades
  • 3,778
  • 1
  • 12
  • 34
  • 4
    Have a look at https://stackoverflow.com/questions/66452781/why-const-char-implicitly-converted-to-bool-rather-than-stdstring - it may explain why, in which case this would be a duplicate. – paxdiablo Jul 16 '22 at 07:56
  • @paxdiablo Oh I just saw my understanding of explicit was wrong. Of course, if conversions from bool and int to ref can't be done implicitly the initialization fails. But still how can I force the use of the string-constructor and why don't clang and msvc complain? It appears to me that this bug could be very nasty – glades Jul 16 '22 at 08:11
  • Easiest way is probably to provide `ref::ref(const char *init) : value_{std::string(init)} {}` or something similar. Not sure off the top of my head if that would work with variants but it'd be the first thing I'd try. – paxdiablo Jul 16 '22 at 08:19
  • yep, clang is doing the same as GCC just not raising a warning: https://godbolt.org/z/r14nvETP9 – Alan Birtles Jul 16 '22 at 08:23
  • I don't think a const char* implicitely converts to a std::string, it can to a "const std::string&" if you replaced with ref::ref(const std::string& init) : value_{init} {}. it would probably also work – Natio2 Jul 16 '22 at 08:24
  • 1
    @Justin [nope](https://godbolt.org/z/T4WK7cEja), still a user defined conversion which loses out to the standard conversion to `bool` – Alan Birtles Jul 16 '22 at 08:26
  • @AlanBirtles Well that's a super interesting behavior to keep in mind for overloading – Natio2 Jul 16 '22 at 08:32
  • @AlanBirtles I notice if you comment out the bool call, it can't handle the const char* to std::string implicit conversion at all. Maybe due to the object wrapping it counts as a second conversion, and it's only allowed to do one implicitely? – Natio2 Jul 16 '22 at 08:40

0 Answers0