import{_ as s,c as t,o as i,ae as a}from"./chunks/framework.l7bN90nj.js";const k=JSON.parse('{"title":"Template Resolver","description":"","frontmatter":{},"headers":[],"relativePath":"design/template-resolver.md","filePath":"en/design/template-resolver.md"}'),n={name:"design/template-resolver.md"};function p(l,e,o,r,h,d){return i(),t("div",null,[...e[0]||(e[0]=[a(`<h1 id="template-resolver" tabindex="-1">Template Resolver <a class="header-anchor" href="#template-resolver" aria-label="Permalink to &quot;Template Resolver&quot;">​</a></h1><p>First, there&#39;s better template support, which is also the feature I initially wanted clangd to support. Specifically, what problems are there currently in handling templates?</p><p>Take code completion as an example. Consider the following code, where <code>^</code> represents the cursor position:</p><div class="language-cpp vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">template</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">typename</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">std</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">vector</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">vec</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">    vec.</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">^</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>In C++, if a type depends on template parameters, we cannot make any accurate assumptions about it before template instantiation. For example, here <code>vector</code> could be either the primary template or the partial specialization of <code>vector&lt;bool&gt;</code>. Which one should we choose? For code compilation, accuracy is always the most important - we cannot use any results that might lead to errors. But for language servers, providing more possible results is often better than providing nothing. We can assume that users use the primary template more often than partial specializations, and thus provide code completion results based on the primary template. Currently, clangd does exactly this - in the above case, it will provide code completion based on the primary template of <code>vector</code>.</p><p>Consider a more complex example:</p><div class="language-cpp vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">template</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">typename</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">std</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">vector</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">std</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">vector</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;&gt; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">vec2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">    vec2[</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">].</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">^</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>From the user&#39;s perspective, completion should also be provided here, since the type of <code>vec2[0]</code> is also <code>vector&lt;T&gt;</code>, right? Same as the previous example. But clangd won&#39;t provide any completion here. What&#39;s the problem? According to the C++ standard, the return type of <code>std::vector&lt;T&gt;::operator[]</code> is <code>std::vector&lt;T&gt;::reference</code>, which is actually a <a href="https://en.cppreference.com/w/cpp/language/dependent_name" target="_blank" rel="noreferrer">dependent name</a>. Its result seems quite direct - it&#39;s <code>T&amp;</code>. But in libstdc++, its definition is nested in dozens of layers of templates, seemingly for compatibility with old standards? So why can&#39;t clangd handle this situation?</p><ol><li>It&#39;s based on primary template assumptions, not considering that partial specializations might make lookup impossible to proceed</li><li>It only performs name lookup without template instantiation, so even if it finds the final result, it can&#39;t map it back to the original template parameters</li><li>It doesn&#39;t consider default template parameters, unable to handle dependent names caused by default template parameters</li></ol><p>Although we can make exceptions for standard library types to provide related support, I hope that user code can have the same status as standard library code, so we need a universal algorithm to handle dependent types. To solve this problem, I wrote a pseudo-instantiation (pseudo instantiator). It can instantiate dependent types without specific types, achieving the purpose of simplification. For example, in the above example, <code>std::vector&lt;std::vector&lt;T&gt;&gt;::reference</code> can be simplified to <code>std::vector&lt;T&gt;&amp;</code>, and further provide code completion options for users.</p>`,10)])])}const m=s(n,[["render",p]]);export{k as __pageData,m as default};
