https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89793
--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> --- Minimal testcase: struct allocator { }; struct string { string(const string&); string(const allocator&); }; struct NotString : allocator { }; struct String { operator string() const; operator NotString() const; }; struct Message { template<typename T> Message(T&& t) : s{t} { } string s; }; int main() { String s; Message m(s); } This is rejected by GCC 8: s.cc: In instantiation of ‘Message::Message(T&&) [with T = String&]’: s.cc:24:14: required from here s.cc:17:25: error: call of overloaded ‘string(<brace-enclosed initializer list>)’ is ambiguous Message(T&& t) : s{t} { } ^ s.cc:5:3: note: candidate: ‘string::string(const allocator&)’ string(const allocator&); ^~~~~~ s.cc:4:3: note: candidate: ‘string::string(const string&)’ string(const string&); ^~~~~~ EDG also rejects it: "s.cc", line 17: error: more than one instance of constructor "string::string" matches the argument list: function "string::string(const string &)" function "string::string(const allocator &)" argument types are: (String) Message(T&& t) : s{t} { } ^ detected during instantiation of "Message::Message(T &&) [with T=String &]" at line 24 It's accepted by Clang.