On Wed, Oct 28, 2026 at 8:56 AM Johannes Kalmbach via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
We stumbled upon this when writing the very last example
```
void f(std::vector<std::string>);
// Convenience overload for a single string
void f(std::string);

for which f({"one", "two"}) is somewhat surprisingly ambiguous, as the string overload is also eligible. 
It could also be silently breaking when refactoring an API from std::vector<std::string> to std::string (because it turned out that one string was enough). 
In that case having a set of constructor arguments that can be used for both types is somewhat surprising, as it is, to my knowledge, not the case for any other
constructor there.

The appropriate fix for this isn't to add a deleted constructor overload to `string`; it's to add the `explicit` keyword to `string`'s two-argument constructor.
https://quuxplusone.github.io/blog/2023/04/08/most-ctors-should-be-explicit/
Now, will there ever be the political will in WG21 to do this? No, definitely not. So I don't think there's anything to be done at the moment.

Implicit conversions due to inappropriately non-explicit constructors are one of the major problems of the STL.
Here's another example that I saw fairly often back in the day (like 2011-ish). Right when initializer-list constructors were a new thing and nobody really understood how to use them yet, it was a common (anti)pattern to wrap STL container initializer-lists in two sets of curly braces. In fact, the way I remember it, often std::array wouldn't compile unless you double-wrapped it (because it's a struct containing an array member, and brace elision wasn't fully implemented everywhere yet). This issue was fixed a long time ago now, of course, and single-curly-braces are 100% correct. But back then, I saw a lot of:

// https://godbolt.org/z/vs9qzPre9
int main() {
    std::vector<int> v1 = {{ 1, 2, 3 }};  // vector of size 3
    std::vector<const char*> v2 = {{ "a", "b", "c" }}; // vector of size 3
    std::vector<std::string> v3 = {{ "a", "b", "c" }}; // vector of size 3
    std::vector<int> v4 = {{ 1, 2 }}; // vector of size 2
    std::vector<const char*> v5 = {{ "a", "b" }}; // vector of size 2
    std::vector<std::string> v6 = {{ "a", "b" }}; // UB goes boom
}

–Arthur