From 5b6d4ea8aba67094c8bbaffdf76ce9d822be1077 Mon Sep 17 00:00:00 2001 From: Brad Arant Date: Sun, 23 Aug 2026 15:11:56 -0700 Subject: [PATCH] Fix ambiguous MString << JString::Proxy overload resolution JString::Proxy offers several implicit conversion operators (ZString, MString, std::string, double, bool) so a single $[...]-style access can be used wherever any of those types is expected. That flexibility made "MString << Proxy" genuinely ambiguous: operator ZString() and operator MString() (via its own implicit upcast to ZString) both satisfy MString::operator<<(ZString), and operator double()/operator bool() both satisfy MString::operator<<(int) via a standard numeric conversion, so the compiler had no basis to prefer one conversion path over another. Fixed the same way Proxy already solves this exact problem for std::cout << proxy - a dedicated friend operator<<(MString&, const Proxy&) that needs no conversion at all, so it's always the preferred candidate. Verified by actually running testing/jstring_test.cpp (not just compiling it) - the line that used to fail to compile now correctly prints "this is a test: this is a comment". Co-Authored-By: Claude Sonnet 5 --- JString.cpp | 7 +++++++ JString.h | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/JString.cpp b/JString.cpp index 3d33461..d75f17f 100644 --- a/JString.cpp +++ b/JString.cpp @@ -12,6 +12,13 @@ namespace coreutils { return os; } + MString &operator<<(MString &ms, const JString::Proxy &proxy) { + ZString tempkey = proxy.key; + ZString temp = proxy.jstring.find(tempkey); + ms << temp; + return ms; + } + JString::JString() : MString("{}") {} // --------------------------------------------------------------------- diff --git a/JString.h b/JString.h index e645d16..62847a0 100644 --- a/JString.h +++ b/JString.h @@ -105,6 +105,23 @@ namespace coreutils { friend std::ostream &operator<<(std::ostream &os, const Proxy &proxy); + /// + /// Proxy offers several implicit conversion operators below (to + /// ZString, MString, std::string, double, bool) so a single $[...]- + /// style access can be used wherever any of those types is expected. + /// That flexibility makes "MString << Proxy" genuinely ambiguous on + /// its own - operator ZString() and operator MString() (via its own + /// implicit upcast to ZString) both satisfy MString::operator<<(ZString), + /// and operator double()/operator bool() both satisfy + /// MString::operator<<(int) via a standard numeric conversion - so + /// the compiler has no way to prefer one path over another. This + /// exact-match overload (mirroring the ostream one above, which + /// solves the same problem for std::cout << proxy) resolves it by + /// giving MString a candidate that needs no conversion at all. + /// + + friend MString &operator<<(MString &ms, const Proxy &proxy); + operator coreutils::ZString () { return jstring.find(key); }