Why do char{} and char() work as a temporary variable for a char* argument?
Asked Answered
S

2

18

In Visual C++ 2017 (with /std:c++14 or with /std:c++17), the following code works:

void TakePtr(char*); // const or not

int main()
{ 
     TakePtr(char{});
     TakePtr(char());
}

I don't understand why it works.

Apparently, the following would also work (as expected):

void TakeChar(char);

   TakeChar(char{});
   TakeChar(char());

How does the compiler deduce (or convert) the type char to char*, when char{} or char() is used as an argument?

Now, if I have both char and char* overloads, it works without any error/warning about ambiguity:

void TakePtr(char*);
void TakePtr(char);

    TakePtr(char{});  // Chooses 'char'
    TakePtr(char());  // Chooses 'char'

Why is the compiler okay with char{} for TakePtr(char*)? And why doesn't it give a warning/error when choosing the better version? Such behavior is bound to break existing code.

For sure, the compiler isn't happy with:

void TakePtr(char*);

    char c{};
    TakePtr(c);
Stomatal answered 21/6, 2019 at 11:28 Comment(8)
A wild guess: char() constructs a temporary (char)0 which is convertible to any integral 0 which is accepted as null pointer. I tested in godbolt, and I believe I'm right: Compiler Explorer.Olympias
@Scheff, xor ecx, ecx; call void TakePtr(char *).Fronia
@Fronia Yepp. That's why I believe I'm right. ;-)Olympias
Might be able to squelch the undesirable behavior by adding void TakePtr(char) = delete;Jook
@Scheff, Bang on! TakePtr(char{8}) fails, TakePtr(char{0}) doesn't.Stomatal
@Eljay, When another overload is present (TakePtr(char) or made not-present by explicit delete, it raises an error. When only one (char*) is present it takes it.Stomatal
Ugh, that is very annoying. I no longer work at Microsoft on Visual Studio, so I am no longer in a position to investigate the problem. For what its worth, clang emits an error.Jook
FWIW, VS2017 and above now has a conformance mode you can turn on to make it more standard compliant. It doesn't help in this case though :(Containment
A
3

This is simply MSVC being behind: the rule in C++03 was that any constant expression of integer type and value 0 was a null pointer constant and could thus be converted to char*. Certainly char() qualifies—and char{} means the same thing, although it never overlapped with the rule.

Actomyosin answered 22/6, 2019 at 0:15 Comment(0)
G
13

Because Visual lies a lot. Especially older one. Your code prompts clang to report an error:

<source>:9:6: error: no matching function for call to 'TakePtr'

     TakePtr(char{});

     ^~~~~~~

<source>:5:6: note: candidate function not viable: no known conversion from 'char' to 'char *' for 1st argument

void TakePtr(char*); // const or not

     ^

<source>:10:6: error: no matching function for call to 'TakePtr'

     TakePtr(char());

     ^~~~~~~

<source>:5:6: note: candidate function not viable: no known conversion from 'char' to 'char *' for 1st argument

void TakePtr(char*); // const or not

     ^

2 errors generated.

Visual is known to be "wonky" in term of following C++ standard, so don't rely on it too much. Try to verify with clang / gcc, just to be sure.

Gerrit answered 21/6, 2019 at 11:34 Comment(0)
A
3

This is simply MSVC being behind: the rule in C++03 was that any constant expression of integer type and value 0 was a null pointer constant and could thus be converted to char*. Certainly char() qualifies—and char{} means the same thing, although it never overlapped with the rule.

Actomyosin answered 22/6, 2019 at 0:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.