{"id":104239,"date":"2020-09-18T07:00:45","date_gmt":"2020-09-18T14:00:45","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104239"},"modified":"2020-09-18T06:55:23","modified_gmt":"2020-09-18T13:55:23","slug":"i-get-a-weird-error-about-no-matching-function-when-i-try-to-use-winrtcapture","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200918-45\/?p=104239","title":{"rendered":"I get a weird error about no matching function when I try to use winrt::capture"},"content":{"rendered":"<p>Last time, we looked at <a title=\"The C++\/WinRT &quot;capture&quot; function helps you interoperate with the COM ABI world\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200917-00\/?p=104230\"> using the C++\/WinRT <code>capture<\/code> to call COM ABI methods from C++\/WinRT<\/a>. But sometimes, you follow the cookbook to the letter, and it still fails:<\/p>\n<pre>winrt::com_ptr&lt;IServiceProvider&gt; provider = ...;\r\n\r\nauto top = winrt::capture&lt;IShellBrowser&gt;\r\n    (provider, &amp;IServiceProvider::QueryService, SID_STopLevelBrowser);\r\n<\/pre>\n<p>Here, we are asking <code>capture<\/code> to invoke the <code>QueryService<\/code> method on the provided <code>IServiceProvider<\/code>, passing <code>SID_STopLevelBrowser<\/code> as the first parameter, and passing a <code>REFIID<\/code> + <code>void**<\/code> pair as the second and third parameters.<\/p>\n<p>And yet, when you try it, you get these strange errors. From the Microsoft compiler:<\/p>\n<pre style=\"white-space: pre-wrap;\">error C2672: 'capture': no matching overloaded function found\r\nerror C2783: 'void capture(F,Args &amp;&amp;...)': could not deduce template argument for 'F'\r\n<\/pre>\n<p>Somehow, the Microsoft compiler thinks we&#8217;re trying to use the functor overload.<\/p>\n<p>From clang:<\/p>\n<pre style=\"white-space: pre-wrap;\">error: no matching function for call to 'capture'\r\n    auto top = winrt::capture&lt;IShellBrowser&gt;\r\n               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\nnote: candidate template ignored: couldn't infer template argument 'O'\r\n    auto capture(com_ptr&lt;O&gt; const&amp; object, M method, Args&amp;&amp;...args)\r\n         ^\r\nnote: candidate template ignored: substitution failure [with T = IShellBrowser, F = winrt::com_ptr&lt;IServiceProvider&gt;]: deduced incomplete pack &lt;(no value), const GUID &amp;&gt; for template parameter 'Args'\r\n        auto capture(F function, Args&amp;&amp;...args)\r\n             ^\r\n<\/pre>\n<p>The gcc compiler says<\/p>\n<pre>error: no matching function for call to 'capture&lt;IShellBrowser&gt;(winrt::com_ptr&lt;IServiceProvider&gt;&amp;, &lt;unresolved overloaded function type&gt;, const GUID&amp;)'\r\n    (provider, &amp;IServiceProvider::QueryService, SID_STopLevelBrowser);\r\n                                                                    ^\r\nnote: candidate: 'auto winrt::capture(F, Args&amp;&amp; ...) [with T = IShellBrowser; F = winrt::com_ptr&lt;IServiceProvider&gt;; Args = {}]'\r\n    auto capture(F function, Args&amp;&amp;...args)\r\n         ^~~~~~~\r\nnote:   candidate expects 1 argument, 3 provided\r\n\r\nnote: candidate: 'template&lt;class T, class O, class M, class ... Args&gt; auto winrt::capture(const winrt::com_ptr&lt;O&gt;&amp;, M, Args&amp;&amp; ...)'\r\n    auto capture(com_ptr&lt;O&gt; const&amp; object, M method, Args&amp;&amp;...args)\r\n         ^~~~~~~\r\nnote:   template argument deduction\/substitution failed:\r\nnote:   couldn't deduce template parameter 'M'\r\n    (provider, &amp;IServiceProvider::QueryService, SID_STopLevelBrowser);\r\n<\/pre>\n<p>What&#8217;s going on?<\/p>\n<p>The Microsoft compiler&#8217;s error message is least helpful. It looks like the Microsoft compiler has selected the functor overload for some reason, but then it rejects the functor because it can&#8217;t deduce the first parameter type <code>F<\/code>. But our first parameter is <code>provider<\/code>, which should be easily deduced to a <code>winrt::com_ptr&lt;IServiceProvider&gt;<\/code>.<\/p>\n<p>It all makes no sense. And why is it not using the overload we want?<\/p>\n<p>The clang error at least tried both overloads, but for the first overload it deduced <code>Args = {}<\/code>, which is strange because we passed a total of three arguments, so the last two should end up in the <code>Args<\/code>. It somehow just lost those arguments in the cushions of the couch or something.<\/p>\n<p>The failed application of the second overload has an enigmatic phrase &#8220;deduced incompete pack \u2329(no value), <code>const GUID &amp;<\/code>\u232a for template parameter &#8216;<code>Args<\/code>&#8216;&#8221;. Somehow, it thinks that <code>&amp;IServiceProvider::QueryService<\/code> has no value?<\/p>\n<p>The gcc error steers us closer to the root cause when it mentions in its error message that the parameter list that it saw was<\/p>\n<pre style=\"white-space: pre-wrap;\">capture&lt;IShellBrowser&gt;(winrt::com_ptr&lt;IServiceProvider&gt;&amp;, &lt;unresolved overloaded function type&gt;, const GUID&amp;)\r\n<\/pre>\n<p>Unresolved overloaded function type. That&#8217;s strange. Let&#8217;s take a closer look at <code>IServiceProvider<\/code>. Here it is, after removing a bunch of RPC and other macro noise:<\/p>\n<pre>MIDL_INTERFACE(\"6d5140c1-7436-11ce-8034-00aa006009fa\")\r\nIServiceProvider : public IUnknown\r\n{\r\npublic:\r\n    virtual HRESULT QueryService( \r\n        REFGUID guidService,\r\n        REFIID riid,\r\n        void **ppvObject) = 0;\r\n    \r\n    template &lt;class Q&gt;\r\n    HRESULT QueryService(REFGUID guidService, Q** pp)\r\n    {\r\n        return QueryService(guidService, __uuidof(Q), (void **)pp);\r\n    }\r\n};\r\n<\/pre>\n<p>Holy cow, somebody added a &#8220;helpful&#8221; overload of <code>IServiceProvider::QueryService<\/code> that takes only two parameters and manufactures the missing <code>REFIID<\/code> parameter.<\/p>\n<p>That&#8217;s why we are getting an error: The expression <code>&amp;IServiceProvider::QueryService<\/code> is ambiguous because it could be referring to the three-parameter method, or it could be referring to an entire family of templated methods (which in turn need to be specialized).<\/p>\n<p>Sometimes being helpful backfires.\u00b9<\/p>\n<p>To be fair, this helpful method was added because the <code>IID_PPV_ARGS<\/code> helper macro hadn&#8217;t yet been invented. Nowadays, people just write<\/p>\n<pre>serviceProvider-&gt;QueryService(guidService, IID_PPV_ARGS(&amp;q));\r\n<\/pre>\n<p>and don&#8217;t even realize that there&#8217;s a helper method available to them.<\/p>\n<p>One way to work around this unwanted helper is to resolve the ambiguity explicitly:<\/p>\n<pre>auto top = winrt::capture&lt;IShellBrowser&gt;\r\n    (provider,\r\n     static_cast&lt;HRESULT (STDMETHODCALLTYPE IServiceProvider::*)(REFGUID, REFIID, void**)&gt;\r\n         (&amp;IServiceProvider::QueryService),\r\n     SID_STopLevelBrowser);\r\n<\/pre>\n<p>This is, however, a horrible monstrosity of a cast.<\/p>\n<p>One option is to use a helper lambda.<\/p>\n<pre>auto top = winrt::capture&lt;IShellBrowser&gt;(\r\n     [](auto&amp;&amp; provider, auto&amp;&amp;... args) { return provider-&gt;QueryService(args...); },\r\n     provider,\r\n     SID_STopLevelBrowser);\r\n<\/pre>\n<p>If you&#8217;re going to be doing this a lot, you can write a helper function:<\/p>\n<pre>inline HRESULT CapturableQueryService(\r\n    IServiceProvider* provider,\r\n    REFGUID service,\r\n    REFIID riid,\r\n    void**ppv)\r\n{\r\n    return provider-&gt;QueryService(service, riid, ppv);\r\n}\r\n\r\nauto top = winrt::capture&lt;IShellBrowser&gt;(CapturableQueryService, provider.get(), SID_STopLevelBrowser);\r\n<\/pre>\n<p>In fact, there&#8217;s a prewritten function that comes with the system that is basically this: <a href=\"https:\/\/docs.microsoft.com\/windows\/win32\/api\/shlwapi\/nf-shlwapi-iunknown_queryservice\"> <code>IUnknown_QueryService<\/code><\/a>. The <code>IUnknown_QueryService<\/code> function is more general, because it accepts an <code>IUnknown*<\/code> as its first parameter and will perform the <code>QueryInterface<\/code> to <code>IServiceProvider<\/code>.<\/p>\n<p>Finally, in what might be the simplest option, you can give the result of that monster cast a name and let everybody use that name.<\/p>\n<pre>inline constexpr HRESULT (STDMETHODCALLTYPE IServiceProvider::*ServiceProviderQueryServiceMethod)(REFGUID, REFIID, void**)\r\n    = &amp;IServiceProvider::QueryService;\r\n\r\nauto top = winrt::capture&lt;IShellBrowser&gt;\r\n    (provider, ServiceProviderQueryServiceMethod, SID_STopLevelBrowser);\r\n<\/pre>\n<p>\u00b9 The <code>IUnknown<\/code> and <code>IAgileReference<\/code> interfaces have the same problem:<\/p>\n<pre>MIDL_INTERFACE(\"00000000-0000-0000-C000-000000000046\")\r\nIUnknown\r\n{\r\npublic:\r\n    virtual HRESULT QueryInterface(\r\n                REFIID riid,\r\n                void **ppvObject) = 0;\r\n    virtual ULONG AddRef(void) = 0;\r\n    virtual ULONG Release(void) = 0;\r\n\r\n    <span style=\"color: blue;\">template&lt;class Q&gt; \r\n    HRESULT\r\n    QueryInterface(Q** pp)\r\n    {\r\n        return QueryInterface(__uuidof(Q), (void **)pp);\r\n    }<\/span>\r\n};                                                                            \r\n\r\nMIDL_INTERFACE(\"C03F6A43-65A4-9818-987E-E0B810D2A6F2\")\r\nIAgileReference : public IUnknown\r\n{\r\npublic:\r\n    virtual HRESULT Resolve(\r\n                REFIID riid,\r\n                void **ppvObjectReference) = 0;\r\n\r\n    <span style=\"color: blue;\">template&lt;class Q&gt; \r\n    HRESULT Resolve(_COM_Outptr_ Q** pp)\r\n    {\r\n        return Resolve(__uuidof(Q), (void **)pp);\r\n    }<\/span>\r\n};\r\n<\/pre>\n<p>However, you are unlikely to run into problems with these interfaces in C++\/WinRT code, because C++\/WinRT already provides native support for <code>IUnknown<\/code> (via <code>com_ptr<\/code>) and <code>IAgileReference<\/code> (via <code>agile_ref<\/code>), so you&#8217;re not going to have to drop to the ABI to use them.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The confusing error message strikes again.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-104239","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The confusing error message strikes again.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=104239"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104239\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=104239"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104239"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}