Is member function of templated class shared?

Started by
4 comments, last by NotAYakk 15 years, 11 months ago
Hi, Let's say I had:

template <typename T, int I>
class foo
{
  void bar()
  {
   std::cout << m_member2 << std::endl;
  }

  int m_member2;
  T m_member;
};

And I created a ton of these... foo<int, 10> a; foo<float, 11> b; foo<double, 440> c; ... Would there only be one implementation of bar(), or would the code bloat to three implementations even if not _technically_ necessary? More specifically, is this an optimization that compilers typically make? I know the type of 'this' will be different depending on the template parameters, and as 'this' is typically passed as a hidden parameter to non-static member functions, there should be multiple versions... but for all intents and purposes, in this case 'this' could be a void* and one bar() implementation could be shared among all foo<T,I> class types. Just hoping to stimulate some discussion... I'm not anything more than curious. :)
--== discman1028 ==--
Advertisement
The compiler has to create 3 different instances, as they're 3 entirely different classes. If one considers template specialisation, they might even have entirely different source code for different template parameters.
However, what is finally written to the executable image may be a different story, that's very implementation dependent. I wouldn't count on it, but it is of course possible for a sufficiently intelligent compiler/linker suite to collapse many binary-identical functions into one. But like I said, that's implementation dependent.

Depending on the model, the compiler might even create many more than just 3 instances (one for every instantiation in every compilation unit) which are later merged by the linker. That would be what's called the "Borland model" which for example g++ uses by default (but can be told to do differently too).
One strategy might be to use "template hoisting": move bar into a non-templated base class.

For example, nodes in linked list may be implemented like this:
struct NodeBase{    NodeBase* next;    NodeBase* prev;    //some member functions that don't rely on the type of node contents};template <class T>struct Node : public NodeBase{    T data;    //member functions that rely on the template parameter};
#include <iostream>template < typename T, int I >struct Foo {  void bar() {    std::cout << quux << '\n';  }  T   baz;<br>  <span class="cpp-keyword">int</span> quux;<br>};<br><br><span class="cpp-keyword">int</span> main() {<br>  Foo&lt; <span class="cpp-keyword">int</span>, <span class="cpp-number">10</span> &gt; a;<br>  Foo&lt; <span class="cpp-keyword">float</span>, <span class="cpp-number">11</span> &gt; b;<br>  Foo&lt; <span class="cpp-keyword">double</span>, <span class="cpp-number">440</span> &gt; c;<br><br>  a.quux = <span class="cpp-number">13</span>;<br>  b.quux = <span class="cpp-number">42</span>;<br>  c.quux = <span class="cpp-number">92</span>;<br><br>  a.bar();<br>  b.bar();<br>  c.bar();<br>}<br><br><br></pre></div><!–ENDSCRIPT–><br><br>I compiled the above code &#111;n GNU GCC 4.3.0 and looked at the assembly output.  It effectively generates this:<pre>int main() {<br>  std::cout &lt;&lt; 13 &lt;&lt; '\n' &lt;&lt; 42 &lt;&lt; '\n' &lt;&lt; 92 &lt;&lt; '\n';<br>}</pre>Given that you need to define <tt>Foo::bar</tt> in a header anyway, it should be very easy for the compiler to inline it, even for more complicated definitions of <tt>bar</tt>, if feasible.
Quote:Original post by discman1028
More specifically, is this an optimization that compilers typically make?

On recent versions of MSVC, you can enable the /OPT:ICF linker option (identical COMDAT folding) and the linker will mush together functions that have identical machine code. I don't know if any other linkers have equivalent behavior.

Incidentally, using this option can make debugging a release build extremely confusing.
Quote:Original post by SiCrane
Quote:Original post by discman1028
More specifically, is this an optimization that compilers typically make?

On recent versions of MSVC, you can enable the /OPT:ICF linker option (identical COMDAT folding) and the linker will mush together functions that have identical machine code. I don't know if any other linkers have equivalent behavior.

Incidentally, using this option can make debugging a release build extremely confusing.

It isn't that confusing once you know about it. It is +very+ confusing when you are surprised by the effect! :)

This topic is closed to new replies.

Advertisement