diff --git a/strings/base_implements.h b/strings/base_implements.h index e545b2a57..ca69bc38b 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -110,10 +110,25 @@ namespace winrt::impl template struct producer_convert : producer::type> { +#ifdef __clang__ + // This is sub-optimal in that it requires an AddRef and Release of the + // implementation type for every conversion, but it works around an + // issue where Clang ignores the conversion of producer_ref const + // to I&& (an rvalue ref that cannot bind a const rvalue). + // See CWG rev. 110 active issue 2077, "Overload resolution and invalid + // rvalue-reference initialization" + operator I() const noexcept + { + I result{ nullptr }; + copy_from_abi(result, (produce::type>*)this); + return result; + } +#else operator producer_ref const() const noexcept { return { (produce::type>*)this }; } +#endif operator producer_vtable const() const noexcept { diff --git a/test/old_tests/UnitTests/as_implements.cpp b/test/old_tests/UnitTests/as_implements.cpp index 4c99631fb..60b27342f 100644 --- a/test/old_tests/UnitTests/as_implements.cpp +++ b/test/old_tests/UnitTests/as_implements.cpp @@ -138,3 +138,13 @@ TEST_CASE("as_implements_inheritance") REQUIRE(bar.get() == foo2.get()); } } + +TEST_CASE("convert_to_implements_via_uniform_initialization") +{ + // uniform initialization relies on IStringable(IStringable&&), + // which requires non-const rvalue semantics. + com_ptr foo = make_self(); + IStringable stringable{ *foo }; + com_ptr foo2 = stringable.as(); + REQUIRE(foo.get() == foo2.get()); +}