{"id":109774,"date":"2024-05-17T07:00:00","date_gmt":"2024-05-17T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109774"},"modified":"2024-08-16T08:59:53","modified_gmt":"2024-08-16T15:59:53","slug":"20240517-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240517-00\/?p=109774","title":{"rendered":"Why can&#8217;t I find the injected name of a templated class&#8217;s templated base class?"},"content":{"rendered":"<p>Some time ago, I wrote about how <a title=\"Injected class names: The C++ feature you didn't even realize that you were using\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220321-00\/?p=106367\"> injected class names were the C++ feature you didn&#8217;t even realize that you were using<\/a>. Injected class names let you use the plain name for the class being defined without needing to fully qualify it with namespaces and template parameters. Furthermore, injected class names are public and can be inherited.<\/p>\n<p>&#8220;But wait, I&#8217;m trying to use the injected class name of my base class, but the compiler won&#8217;t accept it.&#8221;<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Base\r\n{\r\n    Base(T value);\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nstruct Derived : Base&lt;T&gt;\r\n{\r\n    Derived(T value) : Base(value) {}\r\n};\r\n<\/pre>\n<p>This generates a compiler error.<\/p>\n<pre style=\"white-space: pre-wrap;\">\/\/ clang\r\nerror: member initializer 'Base' does not name a non-static data member or base class\r\n\r\n    Derived(T value) : Base(value) {}\r\n                       ^~~~~~~~~~~\r\n\r\n\/\/ gcc\r\nerror: class 'Derived&lt;T&gt;' does not have any field named 'Base'\r\n\r\n    Derived(T value) : Base(value) {}\r\n                       ^~~~\r\n\r\n\/\/ msvc\r\nerror C2512: 'Base&lt;T&gt;': no appropriate default constructor available\r\nerror C2614: illegal member initialization: 'Base' is not a base or member\r\n<\/pre>\n<p>While it&#8217;s true that <code>Base<\/code> is an injected type name of <code>Base<\/code>, it is also a <i>dependent type<\/i>, since its presence is indirectly dependent on the template type parameter <code>T<\/code>. Specifically, the name <code>Base<\/code> is provided by <code>Base&lt;T&gt;<\/code>, and that is dependent on <code>T<\/code>.<\/p>\n<p>Now, you and I can plainly see that no matter how <code>Base&lt;T&gt;<\/code> is defined or specialized, there will always be a type named <code>Base<\/code> that refers to <code>Base&lt;T&gt;<\/code> due to name injection, but the compiler doesn&#8217;t do this sort of fancy logical deduction.<\/p>\n<p>Consider this alternate formulation:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Base\r\n{\r\n    Base(int value);\r\n    using Type = T;\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nstruct Derived : Base&lt;T&gt;\r\n{\r\n    Type m_value;\r\n};\r\n<\/pre>\n<p>Here, <code>Type<\/code> is much more obviously a dependent type, since it is patently dependent on <code>T<\/code>. (And you might have a specialization of <code>Base&lt;T&gt;<\/code> which defines <code>Type<\/code> differently, or maybe doesn&#8217;t even define it at all.)<\/p>\n<p>At the time a template is parsed, non-dependent names are resolved immediately. The dependent names are resolved at the time a template is instantiated. This is known in the jargon as two-phase name lookup. Or as the LLVM blog once called it, the <a title=\"The Dreaded Two-Phase Name Lookup\" href=\"http:\/\/blog.llvm.org\/2009\/12\/dreaded-two-phase-name-lookup.html\"> dreaded<\/a> two-phase name lookup.<\/p>\n<p>One solution is to eschew the injected name and use the original full name:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Derived : Base&lt;T&gt;\r\n{\r\n    Derived(T value) : <span style=\"border: solid 1px currentcolor;\">Base&lt;T&gt;<\/span>(value) {}\r\n};\r\n<\/pre>\n<p>However, this can get clumsy if the base type name is unwieldy, say, because it comes from another namespace, or the template parameters are complex.<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Derived :\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">Contoso::Faraway::Base&lt;                      <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    std::conditional_t&lt;std::is_class_v&lt;T&gt;, T,<\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">        std::tuple&lt;T&gt;&gt;&gt;                      <\/span>\r\n{\r\n    Derived(T value) :\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">Contoso::Faraway::Base&lt;                      <\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\">    std::conditional_t&lt;std::is_class_v&lt;T&gt;, T,<\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">        std::tuple&lt;T&gt;&gt;&gt;<\/span><span style=\"border-top: solid 1px currentcolor;\">(value) {}            <\/span>\r\n};\r\n<\/pre>\n<p>But wait, all is not lost. We just need to postpone the lookup to the second phase by making it a dependent type. And there are two common ways of doing this.<\/p>\n<ul>\n<li>For data members and member functions, explicitly prefix them with <code>this-&gt;<\/code> to make them dependent on the full definition of the template class.<\/li>\n<li>For static members and member types, explicitly scope-qualify them with the name of the template class, and prefixing with <code>typename<\/code> if you&#8217;re looking for a member type.<\/li>\n<\/ul>\n<p>(If you want to access a static data member or static member function, both options are available, since you are allowed to use <code>this<\/code> to access a static data member or static member function.)<\/p>\n<p>Therefore, one solution here is to write<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Derived : Base&lt;T&gt;\r\n{\r\n    Derived(T value) : <span style=\"border: solid 1px currentcolor;\">Derived::<\/span>Base(value) {}\r\n};\r\n<\/pre>\n<p>Another is to explicitly import the type name <code>Base<\/code>:<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct Derived : Base&lt;T&gt;\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">using Base = typename Derived::Base;<\/span>\r\n\r\n    Derived(T value) : Base(value) {}\r\n};\r\n<\/pre>\n<p><b>Additional reading<\/b>: <a title=\"Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?\" href=\"https:\/\/isocpp.org\/wiki\/faq\/templates#nondependent-name-lookup-members\"> Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class<\/a>?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The compiler needs help finding it because it&#8217;s not findable at the time the template is parsed.<\/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-109774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The compiler needs help finding it because it&#8217;s not findable at the time the template is parsed.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109774","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=109774"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109774\/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=109774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}