{"id":110637,"date":"2024-12-13T07:00:00","date_gmt":"2024-12-13T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110637"},"modified":"2024-12-13T13:04:30","modified_gmt":"2024-12-13T21:04:30","slug":"20241213-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241213-00\/?p=110637","title":{"rendered":"Converting to a derived class from the future: How to cast from a base class to an incomplete derived class?"},"content":{"rendered":"<p>A customer had a header-only design in which the clients of the header are expected to derive from the base class with a specific class name. Sort of like <a href=\"https:\/\/en.wikipedia.org\/wiki\/Curiously_recurring_template_pattern\"> CRTP<\/a> without the CR. Or the even the T.<\/p>\n<pre>\/\/ awesome.h\r\n\r\n\/\/ Client is expected to define this class\r\n\/\/ as a derived class of AwesomeAppBase.\r\nstruct AwesomeApp;\r\n\r\nstruct AwesomeAppBase\r\n{\r\n    AwesomeApp* derived()\r\n    { return static_cast&lt;AwesomeApp*&gt;(this); }\r\n\r\n    \/\/ AwesomeApp may override this method to provide\r\n    \/\/ custom preparation work.\r\n    void PrepareForSomething() {}\r\n\r\n    void DoSomething()\r\n    {\r\n        derived()-&gt;PrepareForSomething();\r\n        \u27e6 .. do something ... \u27e7\r\n    }\r\n};\r\n<\/pre>\n<p>This doesn&#8217;t work because <code>Awesome\u00adApp<\/code> is an incomplete type, so the <code>static_cast&lt;AwesomeApp*&gt;(this)<\/code> doesn&#8217;t know how to convert from an <code>Awesome\u00adApp\u00adBase<\/code> to an <code>Awesome\u00adApp<\/code>.<\/p>\n<p>Normally, you would fix this problem by deferring the definition of the methods like <code>derived()<\/code> and <code>Do\u00adSomething()<\/code> to a point after <code>Awesome\u00adApp<\/code> has been defined, but this is a header-only library, so there&#8217;s no chance to provide code later. The header is your only chance.<\/p>\n<p>We can use a trick we saw earlier: <a title=\"C++ template parlor tricks: Using a type before it is defined\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221202-00\/?p=107532\"> Using a type before it is defined<\/a>. In this case, we templatize the methods that depend on the definition of <code>Awesome\u00adApp<\/code> by giving them a template type parameter whose default is the incomplete type.<\/p>\n<pre>struct AwesomeAppBase\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">template&lt;typename T = AwesomeApp&gt;<\/span>\r\n    AwesomeApp* derived()\r\n    { return static_cast&lt;<span style=\"border: solid 1px currentcolor;\">T<\/span>*&gt;(this); }\r\n\r\n    \/\/ AwesomeApp may override this method to provide\r\n    \/\/ custom preparation work.\r\n    void PrepareForSomething() {}\r\n\r\n    <span style=\"border: solid 1px currentcolor;\">template&lt;typename T = AwesomeApp&gt;<\/span>\r\n    void DoSomething()\r\n    {\r\n        derived<span style=\"border: solid 1px currentcolor;\">&lt;T&gt;<\/span>()-&gt;PrepareForSomething();\r\n        \u27e6 .. do something ... \u27e7\r\n    }\r\n};\r\n<\/pre>\n<p>It is, however, rather awkward to have to templatize every method that depends on the <code>Awesome\u00adApp<\/code>. You can remove that awkwardness by templatizing the entire class, transforming it into true CRTP, and then making <code>Awesome\u00adApp\u00adBase<\/code> be an alias for the version of the template with <code>Awesome\u00adApp<\/code> as the derived class.<\/p>\n<pre><span style=\"border: solid 1px currentcolor;\">template&lt;typename T&gt;<\/span>\r\nstruct AwesomeAppBaseT\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">T<\/span>* derived()\r\n    { return static_cast&lt;T*&gt;(this); }\r\n\r\n    \/\/ AwesomeApp may override this method to provide\r\n    \/\/ custom preparation work.\r\n    void PrepareForSomething() {}\r\n\r\n    void DoSomething()\r\n    {\r\n        derived()-&gt;PrepareForSomething();\r\n        \u27e6 .. do something ... \u27e7\r\n    }\r\n};\r\n\r\nusing AwesomeAppBase = AwesomeAppBaseT&lt;AwesomeApp&gt;;\r\n<\/pre>\n<p>You have to be careful to say <code>T<\/code> instead of <code>Awesome\u00adApp<\/code> inside the <code>Awesome\u00adApp\u00adBase\u00adT<\/code> so that you use the dependent type and therefore defer the name lookup until the point the template is instantiated.\u00b9<\/p>\n<p>To remove the temptation to say <code>Awesome\u00adApp<\/code> prematurely, you can move the forward declaration of <code>Awesome\u00adApp<\/code> to appear after the template. And you can even use <code>Awesome\u00adApp<\/code> as the name of the template type parameter, so the code looks &#8220;normal&#8221;.<\/p>\n<pre>template&lt;typename <span style=\"border: solid 1px currentcolor;\">AwesomeApp<\/span>&gt;\r\nstruct AwesomeAppBaseT\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">AwesomeApp<\/span>* derived()\r\n    { return static_cast&lt;AwesomeApp*&gt;(this); }\r\n\r\n    \/\/ AwesomeApp may override this method to provide\r\n    \/\/ custom preparation work.\r\n    void PrepareForSomething() {}\r\n\r\n    void DoSomething()\r\n    {\r\n        derived()-&gt;PrepareForSomething();\r\n        \u27e6 .. do something ... \u27e7\r\n    }\r\n};\r\n\r\n\/\/ Client is expected to define this class\r\n\/\/ as a derived class of AwesomeAppBase.\r\nstruct AwesomeApp;\r\n\r\nusing AwesomeAppBase = AwesomeAppBaseT&lt;AwesomeApp&gt;;\r\n<\/pre>\n<p>If you don&#8217;t want anybody to specialize <code>Awesome\u00adApp\u00adBaseT<\/code> with anything other than <code>Awesome\u00adApp<\/code>, you can move it into a <code>details<\/code> namespace. But it seems useful to let people use the full CRTP form, if they want to give their derived class some other name, or if they want to create more than one derived class. (Say, because they want to have a <code>Contoso\u00adAwesome\u00adApp<\/code> and a <code>Fabrikam\u00adAwesome\u00adApp<\/code> and choose between them at runtime based on a command line switch.)<\/p>\n<p>\u00b9 Note that declaring a type alias does not instantiate the type. According to [<a href=\"https:\/\/timsong-cpp.github.io\/cppwp\/temp.inst\">temp.inst<\/a>], instantiation occurs &#8220;when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program,&#8221; neither of which applies here.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Deferring the definition until the class is complete.<\/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-110637","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Deferring the definition until the class is complete.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110637","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=110637"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110637\/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=110637"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110637"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110637"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}