Skip to content

72 Advanced The Hundred

The String That Became true

one overload too many, and your error message vanishes

#include <iostream>
#include <string>

void log(const std::string& msg) { std::cout << "message: " << msg << '\n'; }
void log(bool verbose) { std::cout << "verbose mode: " << std::boolalpha << verbose << '\n'; }

int main() { log("error: disk full"); }

Run it. What does it print?

Answer

verbose mode: true — the string literal picks the bool overload, and the message is gone.

Why

A string literal is a const char[N] that decays to const char*, and pointer → bool is a standard conversion (any non-null pointer is true). const char*std::string goes through a constructor, making it a user-defined conversion — and overload resolution ranks any standard conversion above any user-defined one, always. How lossy the conversion looks never enters into it. Adding a std::string_view overload does not rescue you: that is a user-defined conversion too, so bool still wins and the output is unchanged. GCC and Clang compile all of this in silence — -Wall -Wextra has nothing to say.

The fix

Give literals an exact match — array-to-pointer decay ranks as an exact match, which beats the pointer-to-bool conversion outright:

void log(const char* msg) { log(std::string(msg)); }   // now: message: error: disk full

Or keep bool out of the overload set entirely: a separate set_verbose(bool) can't hijack anything.

Takeaway: overload resolution ranks conversion kinds, not plausibility — a standard conversion beats a user-defined one, so a literal becomes true before it becomes a std::string.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry