模板链接与前置声明引发的血案
现象:
有一个类模板,它会根据模板类型参数T
的实际类型,调用不同的实例化泛型函数子去处理实际事情。在程序运行时,发现在不同的模块中用相同的类型参数来调用该类模板,得到的结果不一致,也就是说在传入同样的实际模板类型参数实例化了不同的泛型函数子。因此,可以推测在不同的模块中对同样的实际模板类型参数作了不一样的处理,导致生成了不一样的实例化。
问题原型:
为了方便描述,我写了一个能重现这个问题的简化版原型:点此下载源码
模板参数类型类
Base类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Base.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Base { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> ~Base(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* GetName(); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Base.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> Base::~Base() { } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* Base::GetName() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Base"</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
Child类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Child.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Base { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* GetName(); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Child.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Child.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* Child::GetName() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Child"</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
VisibleChild类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// VisibleChild.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> VisibleChild : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Base { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* GetName(); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// VisibleChild.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "VisibleChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* VisibleChild::GetName() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"VisibleChild"</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
使用类模板的类
UsingBase类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingBase.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Template.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> VisibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> UsingBase { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Use(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<Base*> * holder); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<Child*> * holder); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<VisibleChild*> * holder); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingBase.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingBase.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "VisibleChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<Base*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<Child*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<VisibleChild*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Use() { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n=== UsingBase::Use() ===\n"</span>); Base* base = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Base(); Holder<Base*>* hb = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<Base*>(base); Print(hb); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> base; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hb; VisibleChild* visibleChild = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> VisibleChild(); Holder<VisibleChild*>* hc2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<VisibleChild*>(visibleChild); Print(hc2); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> visibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hc2; } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li></ul>
UsingChild类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingChild.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Template.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> VisibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> UsingChild { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Use(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<Child*> * holder); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<VisibleChild*> * holder); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingChild.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingChild.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Child.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "VisibleChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingChild::Print(Holder<Child*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingChild::Print(Holder<VisibleChild*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingChild::Use() { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n=== UsingChild::Use() ===\n"</span>); Child* child = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Child(); Holder<Child*>* hc = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<Child*>(child); Print(hc); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> child; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hc; VisibleChild* visibleChild = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> VisibleChild(); Holder<VisibleChild*>* hc2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<VisibleChild*>(visibleChild); Print(hc2); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> visibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hc2; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li></ul>
类模板:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Template.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <stdio.h></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Helper types Small and Big - guarantee that sizeof(Small) < sizeof(Big)</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> U> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ConversionHelper { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> Small; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> Big { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> dummy[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Big Test(...); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Small Test(U); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> T & MakeT(); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// class template Conversion</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Figures out the conversion relationships between two types</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Invocations (T and U are types):</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// exists: returns (at compile time) true if there is an implicit conversion</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// from T to U (example: Derived to Base)</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Caveat: might not work if T and U are in a private inheritance hierarchy.</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> U> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> Conversion { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> ConversionHelper<T, U> H; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> H::Small) == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>((H::Test(H::MakeT()))) }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists2Way = exists && Conversion<U, T>::exists }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { sameType = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span> }; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Conversion<T, T> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, exists2Way = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, sameType = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span> }; }; <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifndef SUPERSUBCLASS</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define SUPERSUBCLASS(Super, Sub) \</span> (Conversion<Sub, Super>::exists && !Conversion<Super, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*>::sameType) <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">bool</span> isTypeOfBase> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ProcessFunc { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">operator</span>()(T obj) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's not type of Base.\n"</span>); } }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ProcessFunc<T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">operator</span>()(T obj) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's type of Base. GetName: %s\n"</span>, obj->GetName()); } }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Holder { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: Holder(T obj) : mValue(obj) {} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print() { ProcessFunc<T, SUPERSUBCLASS(Base*, T) > func; func(mValue); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>: T mValue; };</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li></ul>
main():
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingBase.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main() { UsingBase ub; ub.Use(); UsingChild uc; uc.Use(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
运行结果:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">=== UsingBase::Use() === It<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'s type of Base. GetName: Base It'</span>s type of Base. GetName: VisibleChild === UsingChild::Use() === It<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'s not type of Base. It'</span>s type of Base. GetName: VisibleChild</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
在 UsingChild::Use()
中,用子类型 Child *
作为类型参数时,类模板没能”正确”实例化,导致它调用了非偏特化的 ProcessFunc
函数子,这不是期望的结果。而用子类型 VisibleChild *
作为类型参数时,类模板正确实例化,得到了我们期望的结果。
分析
为了验证前面的推测:在不同的模块中对同样的实际模板类型参数作了不一样的处理,导致生成了不一样的实例化。下面来分析代码的实际执行过程。
在linux
下,可以用 objdump -S
来查看目标文件或可执行文件的源码与汇编代码对应关系。首先我们来分析可执行文件:TemplateLink
。
objdump -S TemplateLink
首先在 UsingChild::Use() 找到用Child类型作为模板参数的调用点:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000400</span>ba0 <_ZN10UsingChild3UseEv>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingChild::Use() { <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>ba0: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>ba1: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>ba4: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">53</span> push %rbx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>ba5: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">38</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x38</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>ba9: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d c8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x38</span>(%rbp) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n=== UsingChild::Use() ===\n"</span>); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bad: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">88</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0f</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x400f88</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bb2: e8 c9 fa ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400680</span> <<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">puts</span>@plt> Child* child = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Child(); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bb7: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">08</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bbc: e8 ef fa ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4006</span>b0 <_Znwm@plt> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bc1: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c3 mov %rax,%rbx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bc4: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> c7 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">03</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> movq $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0</span>,(%rbx) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bcb: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> df mov %rbx,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bce: e8 e5 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>cb8 <_ZN5ChildC1Ev> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bd3: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>d d0 mov %rbx,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x30</span>(%rbp) Holder<Child*>* hc = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<Child*>(child); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bd7: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">08</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bdc: e8 cf fa ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4006</span>b0 <_Znwm@plt> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>be1: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c3 mov %rax,%rbx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>be4: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> d0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x30</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>be8: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c6 mov %rax,%rsi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>beb: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> df mov %rbx,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bee: e8 eb <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>cde <_ZN6HolderIP5ChildEC1ES1_> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bf3: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>d d8 mov %rbx,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x28</span>(%rbp) Print(hc); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bf7: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> d8 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x28</span>(%rbp),%rdx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bfb: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> c8 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x38</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>bff: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> d6 mov %rdx,%rsi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c02: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c7 mov %rax,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c05: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>a ff ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b64 <_ZN10UsingChild5PrintEP6HolderIP5ChildE> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> child; <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c0a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d d0 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> cmpq $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0</span>,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x30</span>(%rbp) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c0f: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">74</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span> je <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c28 <_ZN10UsingChild3UseEv+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x88</span>> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c11: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> d0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x30</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c15: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (%rax),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c18: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> c0 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">08</span> add $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>,%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c1c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (%rax),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c1f: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> d0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x30</span>(%rbp),%rdx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c23: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> d7 mov %rdx,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c26: ff d0 callq *%rax <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hc; <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c28: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> d8 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x28</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c2c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c7 mov %rax,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>c2f: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>c fa ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400690</span> <_ZdlPv@plt></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li></ul>
这个调用点就是 Print(hc)
,C++默认是将this作为第一个参数,所以源码中的hc->Print()
在这里就对应C形式的Print(hc)
。找到其对应的符号_ZN10UsingChild5PrintEP6HolderIP5ChildE
,然后使用这个符号在dump信息中找到对应的代码:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000400</span>b64 <_ZN10UsingChild5PrintEP6HolderIP5ChildE>: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingChild.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Child.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "VisibleChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingChild::Print(Holder<Child*> * holder) { <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b64: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b65: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b68: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b6c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d f8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>(%rbp) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b70: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">75</span> f0 mov %rsi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp) holder->Print(); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b74: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> f0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b78: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c7 mov %rax,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b7b: e8 d4 fe ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a54 <_ZN6HolderIP5ChildE5PrintEv> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b80: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b81: c3 retq</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
在这里是转调holder->Print();
,找到其对应的符号_ZN6HolderIP5ChildE5PrintEv
,然后使用这个符号在dump信息中找到对应的代码:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000400</span>a54 <_ZN6HolderIP5ChildE5PrintEv>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: Holder(T obj) : mValue(obj) {} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print() <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a54: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a55: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a58: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x20</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a5c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d e8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x18</span>(%rbp) { ProcessFunc<T, SUPERSUBCLASS(Base*, T) > func; func(mValue); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a60: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> e8 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x18</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a64: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> mov (%rax),%rdx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a67: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>d <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> ff lea -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x1</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a6b: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> d6 mov %rdx,%rsi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a6e: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c7 mov %rax,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a71: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">96</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b0c <_ZN11ProcessFuncIP5ChildLb0EEclES1_> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a76: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>a77: c3 retq</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
在这里是根据模板参数类型实例化的泛型函数子来分发的:ProcessFunc<T, SUPERSUBCLASS(Base*, T) > func; func(mValue);
,找到其对应的符号_ZN11ProcessFuncIP5ChildLb0EEclES1_
,然后使用这个符号在dump信息中找到最终执行的代码:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000400</span>b0c <_ZN11ProcessFuncIP5ChildLb0EEclES1_>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">bool</span> isTypeOfBase> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ProcessFunc { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">operator</span>()(T obj) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b0c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b0d: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b10: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b14: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d f8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>(%rbp) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b18: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">75</span> f0 mov %rsi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's not type of Base.\n"</span>); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b1c: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">70</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0f</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x400f70</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b21: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>a fb ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400680</span> <<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">puts</span>@plt> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b26: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b27: c3 retq</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>
从这段代码可以看到:用Child *
类型作为类模板参数时,实例化了非偏特化的泛型函数子ProcessFunc
,从而显示了非期望的结果It's not type of Base.\n
。
用同样的方式,可以找到用VisibleChild
类型作为类模板参数时,实例化了的偏特化的泛型函数子ProcessFunc
:
<code class="hljs perl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000400</span>b28 <_ZN11ProcessFuncIP12VisibleChildLb1EEclES1<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">_</span>>: }; template<class T> struct ProcessFunc<T, true> { void operator()(T obj) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b28: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">push</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rbp</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b29: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rsp</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rbp</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b2c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> <span class="hljs-sub" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sub</span> $0x10,%rsp 400b30: 48 89 7d f8 mov %rdi,-0x8(%rbp) 400b34: 48 89 75 f0 mov %rsi,-0x10(%rbp) {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's type of Base. GetName: <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%s</span>\n"</span>, obj->GetName()); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b38: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> f<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rbp</span>),<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b3c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span>),<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b3f: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> c<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> add <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$0</span>x1<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b43: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span>),<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b46: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> f<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rbp</span>),<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rdx</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b4a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> d7 mov <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rdx</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rdi</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b4d: ff d<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> callq <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*%</span>rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b4f: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c6 mov <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rax</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%rsi</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b52: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span> 0f <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">40</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$0</span>x400f5<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%edi</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b57: b8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$0</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">x</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">%eax</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b5c: e8 ff fa ff ff callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400660</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">printf</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@plt</span>> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b61: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b62: c3 retq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">400</span>b63: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">90</span> nop</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>
至此,可以推断分别用Child *
和VisibleChild *
作为类模板参数时,导致了对另一个类模板参数bool isTypeOfBase
的不同推导结果。对于Child *
类型来说:SUPERSUBCLASS(Base*, Child*)
推导为false
;而对于VisibleChild *
类型来说:SUPERSUBCLASS(Base*, VisibleChild*)
推导为’true’。它们都是Base
的子类,却推导出不同的结果,何其诡异呀!
SUPERSUBCLASS 分析
SUPERSUBCLASS
是一个宏:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifndef SUPERSUBCLASS</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define SUPERSUBCLASS(Super, Sub) \</span> (Conversion<Sub, Super>::exists && !Conversion<Super, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*>::sameType) <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
它返回 Sub
是否可以隐式转换为 Super
类型,且 Super
不得是 void*
类型。这个转换判断操作是泛型类Conversion
来完成的:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> U> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ConversionHelper { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> Small; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> Big { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> dummy[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Big Test(...); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Small Test(U); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> T & MakeT(); }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> U> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> Conversion { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> ConversionHelper<T, U> H; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> H::Small) == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>((H::Test(H::MakeT()))) }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists2Way = exists && Conversion<U, T>::exists }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { sameType = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span> }; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Conversion<T, T> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> { exists = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, exists2Way = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>, sameType = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span> }; }; <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>
如果MakeT()
返回的类型参数 T
能够隐式地转换为 ‘U’,那么就会调用 ‘Small Test(U)’ 返回 Small
,从而exists
为 true
;否则如果不能隐式地转换为 ‘U’,就会调用重载的 Big Test(...)
返回 ‘Big’,从而exists
为 false
。
在这里,类型 Child *
被认为不能隐式转换为 ‘Base *’,导致了非期望的结果。至于为什么,下文会有分析。
objdump -S UsingBase.o
我们知道模板实例化只会在第一次用到的时候才会进行,接下来就穷追猛打,看看到底用Child *
作为类型参数实例化了什么样的类。在这个示例代码中,有两处用到了Holder<Child*> * holder
: UsingBase
和 UsingChild
,下面来分析它们。
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Disassembly of section .text._ZN11ProcessFuncIP5ChildLb0EEclES1_: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000000000</span> <_ZN11ProcessFuncIP5ChildLb0EEclES1_>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">bool</span> isTypeOfBase> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ProcessFunc { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">operator</span>()(T obj) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d f8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>(%rbp) c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">75</span> f0 mov %rsi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's not type of Base.\n"</span>); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>a <_ZN11ProcessFuncIP5ChildLb0EEclES1_+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x1a</span>> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>a: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>b: c3 retq</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
注意看符号 _ZN11ProcessFuncIP5ChildLb0EEclES1_
,这正是前面非期望情况下调用的版本。也就是说用Child *
作为模板类型参数最终调用的是这个实例化版本。
objdump -S UsingChild.o
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Disassembly of section .text._ZN11ProcessFuncIP5ChildLb1EEclES1_: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0000000000000000</span> <_ZN11ProcessFuncIP5ChildLb1EEclES1_>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> ProcessFunc<T, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">operator</span>()(T obj) <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> push %rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> e5 mov %rsp,%rbp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> ec <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> sub $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>,%rsp <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>d f8 mov %rdi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x8</span>(%rbp) c: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">75</span> f0 mov %rsi,-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"It's type of Base. GetName: %s\n"</span>, obj->GetName()); <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">45</span> f0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (%rax),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">83</span> c0 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> add $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>,%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>b: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov (%rax),%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>e: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>b <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">55</span> f0 mov -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x10</span>(%rbp),%rdx <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">22</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> d7 mov %rdx,%rdi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">25</span>: ff d0 callq *%rax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">27</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">48</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">89</span> c6 mov %rax,%rsi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>a: bf <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0</span>,%edi <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2f</span>: b8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> mov $<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0</span>,%eax <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">34</span>: e8 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">00</span> callq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39</span> <_ZN11ProcessFuncIP5ChildLb1EEclES1_+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x39</span>> } <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39</span>: c9 leaveq <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>a: c3 retq</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>
注意看符号 _ZN11ProcessFuncIP5ChildLb1EEclES1_
,它和上面objdump -S UsingBase.o
中的符号_ZN11ProcessFuncIP5ChildLb0EEclES1_
仅有一字之差:名称中间的索引 Lb0
和 Lb1
。这个实例化版本才是期望被调用的版本。
那么问题就来了:
问题一:为什么有两个实例化版本,而链接到可执行程序中又只有一个版本?
问题二:为什么UsingBase.o
中没能实例化出期望的版本?
问题解答
解答问题一
编译器会在每一个用到模板的编译单元中用实际模板参数进行实例化,这样在多个编译单元中可能会存在对相同模板参数的实例化版本,它们的符号命名中带有索引标识(如上面的 Lb0
和 Lb1
)。在链接阶段,编译会根据链接顺序剔除重复的实例化版本,最终针对每一个类模板参数只有一份实例化版本。在这里被剔除的实例化版本是UsingChild
中的_ZN11ProcessFuncIP5ChildLb1EEclES1_
,而留下的是 UsingBase
中的_ZN11ProcessFuncIP5ChildLb0EEclES1_
。
解答问题二
在 UsingBase
中,对于Child *
类型来说:SUPERSUBCLASS(Base*, Child*)
被推导为 false
。为什么会这样呢?再来仔细看看 UsingBase
的实现:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingBase.h</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Template.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "Base.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> VisibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> UsingBase { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Use(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<Base*> * holder); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<Child*> * holder); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print(Holder<VisibleChild*> * holder); }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// UsingBase.cpp</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "UsingBase.h"</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "VisibleChild.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<Base*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<Child*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Print(Holder<VisibleChild*> * holder) { holder->Print(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> UsingBase::Use() { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n=== UsingBase::Use() ===\n"</span>); Base* base = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Base(); Holder<Base*>* hb = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<Base*>(base); Print(hb); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> base; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hb; VisibleChild* visibleChild = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> VisibleChild(); Holder<VisibleChild*>* hc2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Holder<VisibleChild*>(visibleChild); Print(hc2); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> visibleChild; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> hc2; } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li></ul>
可以看到在 UsingBase
这个编译单元中,Child
只有前置声明,它是一个外部未定义的符号,看不到它的类型信息。因此 Child *
被当做普通的指针看待,因而 Conversion<Child *, Base *>::exists
被推导为 false,从而实例化了非偏特化的 ProcessFunc
版本,产生了问题。如果需要达到期望的效果,就必须看到 Child
的完整类型信息。
解决方案
针对这个 Child
个例,可以在 UsingBase.h
或 UsingBase.cpp
中添加头文件来消除这个 bug。但这并非通用的解决方案,因为没有根本解决泛型函数子 ProcessFunc<T, SUPERSUBCLASS(Base*, T) >
第二个参数正确推导的问题,也就是说我们需要逼着模板类型参数 T 提前显示它的完整类型信息。如果我们修改为某种类似SUPERSUBCLASS(Base, Child)
的判断方式,就可以达到这一目的。这是可以实现的,通过使用类型萃取技法,我们可以从模板参数 T 萃取它包含的裸类型(bare type)或值类型。
类型萃取辅助类:
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> HolderItem { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> T ValueType; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> HolderItem> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> TypeTraits { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> HolderItem::ValueType ValueType; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> TypeTraits<T*> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> T ValueType; }; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> TypeTraits<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> T*> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> T ValueType; };</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
应用
修改之后的 Holder :
<code class="language-cpp hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "TypeOp.h"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">template</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Holder { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>: Holder(T obj) : mValue(obj) {} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> Print() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typename</span> TypeTraits<T>::ValueType CompleteType; ProcessFunc<T, SUPERSUBCLASS(Base, CompleteType) > func; func(mValue); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>: T mValue; };</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
做出修改这样的修改之后,再次编译运行,就会得到编译错误信息:
<code class="hljs vbnet has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">../Template.h: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">In</span> instantiation <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span> ‘struct Conversion<Child, Base>’: ../Template.h:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">85</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>: required <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> ‘void Holder<T>::Print() [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> T = Child*]’ ../UsingBase.cpp:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">19</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">19</span>: required <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> here ../Template.h:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">73</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span>: invalid use <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span> incomplete type ‘<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child’ exists = sizeof(typename H::Small) == sizeof((H::Test(H::MakeT()))) ^ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">In</span> file included <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> ../UsingBase.cpp:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>: ../UsingBase.h:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span>: forward declaration <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span> ‘<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child’ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Child; ^ make: *** [UsingBase.o] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Error</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
这样就能将问题提前抛出,从而定位出需要修改的地方。
不足
这种提前抛出问题的解决方案,并非完美,因为它是通过将判断 Conversion<Child *, Base *>::exists
转换为判断 Conversion<Child, Base>::exists
来实现的,而 T & MakeT() 或
Small Test(U)` 对后者有更严格的限制:必须能够存在 T 的对象和 U 的对象,也就是说 T 和 U 不能有纯虚方法。