C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Proposal: Disallow string(_view) construction from two literals

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Wed, 28 Oct 2026 16:31:51 +0100
Could compilers warn, if both possibilities, what is meant by the programmer, exist? (Even if the standard defines, which is meant) And we use unique (for one of the cases) syntax to avoid the compiler warning?   -----Ursprüngliche Nachricht----- Von:Jonathan Wakely via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Mi 28.10.2026 16:07 Betreff:Re: [std-proposals] Proposal: Disallow string(_view) construction from two literals An:std-proposals_at_[hidden]; CC:Jonathan Wakely <cxx_at_[hidden]>;   On Wed, 28 Oct 2026 at 13:55, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> > wrote: On Wed, Oct 28, 2026 at 8:56 AM Johannes Kalmbach via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> > 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  Yes, the problem OP wants to solve for string and string_view is much broader than just those two constructors.   }    Tangentially, initializer-list constructors would have avoided some of their problems if we had actually required the braces to be inside parens or another set of braces, so that std::vector<int>({1,2}) was how you called a constructor with a std::initializer_list, and std::vector<int>{1,2} was unambiguously the vector(size_type, const T&) constructor. Or we could have just never introduced "uniform" init at all, and braces would only work for aggregates and for std::initializer_list temporaries, then std::vector<int>{1,2} would just be ill-formed. Sigh. -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals  

Received on 2026-10-28 15:32:49