{"id":6341,"date":"2022-04-07T17:31:31","date_gmt":"2022-04-07T17:31:31","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/type-erasure\/"},"modified":"2023-06-26T09:09:03","modified_gmt":"2023-06-26T09:09:03","slug":"type-erasure","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/type-erasure\/","title":{"rendered":"Type Erasure"},"content":{"rendered":"<p><span lang=\"DE\"> Type erasure based on templates is a pretty sophisticated technique. It bridges dynamic polymorphism (object orientation) with static polymorphism (templates).<br \/><\/span><\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6320\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/03\/PolicyAndTraits.png\" alt=\"\" width=\"650\" height=\"398\" style=\"display: block; margin-left: auto; margin-right: auto;\" data-alt=\"PolicyAndTraits\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/03\/PolicyAndTraits.png 907w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/03\/PolicyAndTraits-300x184.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/03\/PolicyAndTraits-768x470.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>First: What does type erasure mean?<\/p>\n<ul>\n<li><strong>Type Erasure: <\/strong>Type Erasure enables using various concrete types through a single generic interface.<\/li>\n<\/ul>\n<p>You already quite often used type erasure in C++ or C. The C-ish type erasure is a void pointer; object orientation is the classical C++-ish way of type erasure. Let&#8217;s start with a <code>void<\/code> pointer.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Void_Pointer\"><\/span><code>Void<\/code> Pointer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s have a closer look at the declaration of <code>std::qsort<\/code>:<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">qsort<\/span>(<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>ptr, std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> count, std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> size, cmp);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>with:<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">cmp<\/span>(<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>a, <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #555555;\">*<\/span>b);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The comparison function <code>cmp <\/code>should return a<\/p>\n<ul>\n<li>negative integer: the&nbsp;first argument is less than the second<\/li>\n<li>zero: both arguments are equal<\/li>\n<li>positive integer: the&nbsp;first argument is greater than the second<\/li>\n<\/ul>\n<p>Thanks to the <code>void<\/code> pointer, <code>std::qsort<\/code> is generally applicable but also quite error-prone.<\/p>\n<p>Maybe you want to sort a <code>std::vector&lt;int&gt;,<\/code> but you used a comparator for C-strings. The compiler can not catch this error because the necessary type information is missing. Consequentially, you end with undefined behavior.<\/p>\n<p>In C++, we can do better:<\/p>\n<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Object_Orientation\"><\/span>Object Orientation<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Here is a straightforward example, which serves as a starting point for further variation.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ typeErasureOO.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> BaseClass{                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\t<span style=\"color: #006699; font-weight: bold;\">virtual<\/span> std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Bar<span style=\"color: #555555;\">:<\/span> BaseClass{                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n\tstd<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n\t    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Bar\"<\/span>;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Foo<span style=\"color: #555555;\">:<\/span> BaseClass{                                  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n\tstd<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override{\r\n\t    <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Foo\"<\/span>;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">printName<\/span>(std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> BaseClass<span style=\"color: #555555;\">*&gt;<\/span> vec){      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> v<span style=\"color: #555555;\">:<\/span> vec) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> v<span style=\"color: #555555;\">-&gt;<\/span>getName() <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n}\r\n\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n\t\r\n\tstd<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n\t\r\n\tFoo foo;\r\n\tBar bar; \r\n\t\r\n\tstd<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> BaseClass<span style=\"color: #555555;\">*&gt;<\/span> vec{<span style=\"color: #555555;\">&amp;<\/span>foo, <span style=\"color: #555555;\">&amp;<\/span>bar};   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n\t\r\n\tprintName(vec);\r\n\t\r\n\tstd<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt; <\/span>'\\n';\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><code>std::vector&lt;const Base*&gt;<\/code> (line 1) has a pointer to a constant <code>BaseClass<\/code>. <code>BaseClass<\/code> is an abstract base class used in line (3). <code>Foo<\/code> and <code>Bar<\/code> (line 4) are the concrete classes.<\/p>\n<p>The output of the program is as expected.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5498\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO.png\" alt=\"typeErasureOO\" width=\"350\" height=\"208\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO.png 612w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/typeErasureOO-300x178.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p id=\"firstHeading\" class=\"firstHeading\" lang=\"en\">To say it more formally. <code>Foo <\/code>and <code>Bar <\/code>implement the interface of the <code>BaseClass <\/code>and can, therefore, be used instead of BaseClass<code>.<\/code> This principle is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Liskov_substitution_principle\">Liskov substitution principle<\/a> and is type erasure in OO.<\/p>\n<p>In object-orientated programming, you implement an interface. In generic programmings, such as templates, you are not interested in interfaces; you are interested in behavior. In my previous post, &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/dynamic-and-static-polymorphism\">Dynamic and Static Polymorphism<\/a>&#8220;, read more about the difference between interface-driven and behavior-driven design.<\/p>\n<p>Type erasure with templates bridges the gap between dynamic polymorphism and static polymorphism.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Type_Erasure\"><\/span>Type Erasure<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let me start with a prominent example of type erasure:<code> std::function<\/code>.<code> std::function<\/code> is a polymorphic function wrapper. It can accept everything that behaves like a function. To be more precise. This everything can be any callable such as a function, a function object, a function object created by <code>std::bind<\/code>, or just a lambda expression.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ callable.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;cmath&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;functional&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;map&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #cc00ff;\">add<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){\r\n\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">+<\/span> b;\r\n}\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Sub{\r\n\t<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span>()(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){\r\n\t\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">-<\/span> b;\r\n\t}\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">double<\/span> <span style=\"color: #cc00ff;\">multThree<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b, <span style=\"color: #007788; font-weight: bold;\">double<\/span> c){\r\n\t<span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">*<\/span> b <span style=\"color: #555555;\">*<\/span> c;\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n    \r\n    <span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span> std<span style=\"color: #555555;\">::<\/span>placeholders;\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>map<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">char<\/span> , std<span style=\"color: #555555;\">::<\/span>function<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span>(<span style=\"color: #007788; font-weight: bold;\">double<\/span>, <span style=\"color: #007788; font-weight: bold;\">double<\/span>)<span style=\"color: #555555;\">&gt;&gt;<\/span> dispTable{  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        {<span style=\"color: #cc3300;\">'+'<\/span>, add },                                         <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n        {<span style=\"color: #cc3300;\">'-'<\/span>, Sub() },                                       <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n        {<span style=\"color: #cc3300;\">'*'<\/span>, std<span style=\"color: #555555;\">::<\/span>bind(multThree, <span style=\"color: #ff6600;\">1<\/span>, _1, _2) },             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n        {<span style=\"color: #cc3300;\">'\/'<\/span>,[](<span style=\"color: #007788; font-weight: bold;\">double<\/span> a, <span style=\"color: #007788; font-weight: bold;\">double<\/span> b){ <span style=\"color: #006699; font-weight: bold;\">return<\/span> a <span style=\"color: #555555;\">\/<\/span> b; }}};      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 + 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'+'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 - 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'-'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 * 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'*'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"3.5 \/ 4.5 = \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> dispTable[<span style=\"color: #cc3300;\">'\/'<\/span>](<span style=\"color: #ff6600;\">3.5<\/span>, <span style=\"color: #ff6600;\">4.5<\/span>) <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>In this example, I use a dispatch table (line 1) that maps characters to callables. A callable can be a function (line 1), a function object (lines 2 and 3), a function object created by <code>std::bind<\/code> (line 4), or a lambda expression (line 5). The key point of <code>std::function<\/code> is that it accepts all different <em>function-like types<\/em> and erases their types. <code>std::function<\/code> requires from its callable that it takes two <code>double's<\/code> and returns a <code>double: std::function&lt;double(double, double)&gt;.<\/code><\/p>\n<p>To complete the example, here is the output.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5500\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable.png\" alt=\"callable\" width=\"350\" height=\"240\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable.png 379w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/09\/callable-300x206.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/>After this first introduction to type erasure, I want to implement the program <code>typeErasureOO.cpp<\/code> using type erasure based on templates.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ typeErasure.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;memory&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">Object<\/span> {                                              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n\t \r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>                                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    Object(<span style=\"color: #006699; font-weight: bold;\"><\/span>T<span style=\"color: #555555;\">&amp;&amp;<\/span> obj)<span style=\"color: #555555;\">:<\/span> object(std<span style=\"color: #555555;\">::<\/span>make_shared<span style=\"color: #555555;\">&lt;<\/span>Model<span style=\"color: #555555;\">&lt;<\/span>T<span style=\"color: #555555;\">&gt;&gt;<\/span>(std<span style=\"color: #555555;\">::forward&lt;T&gt;<\/span>(obj))){}\r\n      \r\n    std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> object<span style=\"color: #555555;\">-&gt;<\/span>getName(); \r\n    }\r\n\t\r\n   <span style=\"color: #006699; font-weight: bold;\">struct<\/span> Concept {                                         <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n       <span style=\"color: #006699; font-weight: bold;\">virtual<\/span> <span style=\"color: #555555;\">~<\/span>Concept() {}\r\n       <span style=\"color: #006699; font-weight: bold;\">virtual<\/span> std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">0<\/span>;\r\n   };\r\n\r\n   <span style=\"color: #006699; font-weight: bold;\">template<\/span><span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T <span style=\"color: #555555;\">&gt;<\/span>                                   <span style=\"color: #0099ff; font-style: italic;\">\/\/ (6)<\/span>\r\n   <span style=\"color: #006699; font-weight: bold;\">struct<\/span> Model <span style=\"color: #555555;\">:<\/span> Concept {\r\n       Model(<span style=\"color: #006699; font-weight: bold;\">const<\/span> T<span style=\"color: #555555;\">&amp;<\/span> t) <span style=\"color: #555555;\">:<\/span> object(t) {}\r\n\t   std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> override {\r\n\t\t   <span style=\"color: #006699; font-weight: bold;\">return<\/span> object.getName();\r\n\t   }\r\n     <span style=\"color: #9999ff;\">private:<\/span>\r\n       T object;\r\n   };\r\n\r\n   std<span style=\"color: #555555;\">::<\/span>shared_ptr<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">const<\/span> Concept<span style=\"color: #555555;\">&gt;<\/span> object;\r\n};\r\n\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">printName<\/span>(std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>Object<span style=\"color: #555555;\">&gt;<\/span> vec){                    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (7)<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #006699; font-weight: bold;\">auto<\/span> v<span style=\"color: #555555;\">:<\/span> vec) std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> v.getName() <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n}\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Bar{\r\n    std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (8)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Bar\"<\/span>;\r\n    }\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Foo{\r\n    std<span style=\"color: #555555;\">::<\/span>string getName() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                           <span style=\"color: #0099ff; font-style: italic;\">\/\/ (8)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Foo\"<\/span>;\r\n    }\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n\t\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n\t\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>Object<span style=\"color: #555555;\">&gt;<\/span> vec{Object(Foo()), Object(Bar())};  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n\t\r\n    printName(vec);\r\n\t\r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> '\\n';\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Okay, what is happening here? Don&#8217;t be irritated by the names <code>Object<\/code>, <code>Concept<\/code>, and <code>Model<\/code>. They are typically used for type erasure in the literature. So I stick with them.<\/p>\n<p><code>std:<\/code>:vector uses instances (line 1) of type <code>Object<\/code> (line 2) and not pointers, such as in the first OO example. These instances can be created with arbitrary types because they have a generic constructor (line 3). <code>Object<\/code> has the member function <code>getName<\/code> (4) that directly forwards to the <code>getName <\/code>of <code>object<\/code>. <code>object<\/code> is of type <code>std::shared_ptr&lt;const Concept&gt;<\/code>. The member function <code>getName <\/code>of <code>Concept<\/code> is pure virtual (line 5).&nbsp;Therefore, the <code>getName<\/code> member function of <code>Model<\/code> (line 6) is used due to virtual dispatch. The <code>getName <\/code>member functions of <code>Bar <\/code>and <code>Foo <\/code>(line 8) are applied in the <code>printName <\/code>function (line 7).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6336\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasureRun.png\" alt=\"typeErasure\" width=\"350\" height=\"208\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasureRun.png 612w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasureRun-300x178.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/>Of course, this implementation is type-safe. So what happens in case of an error:<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Error_messages\"><\/span>Error messages<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Here is the incorrect implementation:<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">struct<\/span> Bar{\r\n    std<span style=\"color: #555555;\">::<\/span>string get() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Bar\"<\/span>;\r\n    }\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Foo{\r\n    std<span style=\"color: #555555;\">::<\/span>string get_name() <span style=\"color: #006699; font-weight: bold;\">const<\/span> {                        <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n        <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #cc3300;\">\"Foo\"<\/span>;\r\n    }\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I renamed the method <code>getName <\/code>of <code>Bar <\/code>and <code>Foo<\/code> to <code>get <\/code>(line 1) and to <code>get_name<\/code> (line 2).<code>&nbsp;<\/code><\/p>\n<p>Here are the error messages, copied with the<a href=\"https:\/\/godbolt.org\/z\/b4xrGPnve\"> Compiler Explorer<\/a><a href=\"https:\/\/godbolt.org\/\">. <\/a><\/p>\n<p>All three compilers, g++, clang++, and MS compiler cl.exe, come directly to the point.<\/p>\n<h4>Clang 14.0.0<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6337\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang.jpg\" alt=\"clang\" width=\"650\" height=\"95\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang.jpg 2094w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang-300x44.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang-1024x149.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang-768x111.jpg 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang-1536x223.jpg 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/clang-2048x297.jpg 2048w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<h4>GCC 11.2<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6338\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-scaled.jpg\" alt=\"gcc\" width=\"650\" height=\"62\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-scaled.jpg 2560w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-300x28.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-1024x97.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-768x73.jpg 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-1536x146.jpg 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/gcc-2048x194.jpg 2048w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>&nbsp;<\/p>\n<h4>MSVC 19.31<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6339\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc.jpg\" alt=\"msvc\" width=\"650\" height=\"46\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc.jpg 2459w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc-300x21.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc-1024x72.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc-768x54.jpg 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc-1536x109.jpg 1536w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/msvc-2048x145.jpg 2048w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>What are the pros and cons of these three techniques for type erasure?<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Pros_and_Cons\"><\/span>Pros and Cons<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6340\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasure.png\" alt=\"PolicyAndTraits\" width=\"1054\" height=\"177\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasure.png 1054w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasure-300x50.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasure-1024x172.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2022\/04\/typeErasure-768x129.png 768w\" sizes=\"auto, (max-width: 1054px) 100vw, 1054px\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"void_Pointer\"><\/span><code>void<\/code> Pointer<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><code>void<\/code> Pointers are the C-ish way to provide one interface for different types. They give you complete flexibility. You don&#8217;t need a base class; they are easy to implement. On the contrary, you lose all type information and, therefore, type safety.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Object_Orientation-2\"><\/span>Object Orientation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Object orientation is the C++-is way to provide one interface for different types. If you are accustomed to object-orientated programming, this is your typical way to design software systems. OO is challenging to implement but type-safe. It requires an interface and publicly derived implementations.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Type_Erasure-2\"><\/span>Type Erasure<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Type erasure is a type-safe generic way to provide one interface for different types. The different types don&#8217;t need a common base class and are unrelated.&nbsp; Type erasure is pretty sophisticated to implement.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Performance\"><\/span>Performance<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>I ignored one point in my comparison: performance. Object orientation and type erasure are based on virtual inheritance. Consequentially, there is one pointer indirection happening at run time. Does this mean object orientation and type erasure is slower than the void Pointer? I&#8217;m not sure. You have to measure it in the concrete use case. When you use a void Pointer, you lose all type information. Therefore, the compiler can not make assumptions about the used types and generate optimized code. The performance questions can only be answered with a performance test.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Whats_Next\"><\/span>What&#8217;s Next?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I wrote almost 50 posts about <a href=\"https:\/\/www.modernescpp.com\/index.php\/category\/templates\">templates <\/a>in the last year. During that time, I learned a lot more about C++20. Therefore, I continue to write about C++20 and peek into the next C++ standard: C++23.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Type erasure based on templates is a pretty sophisticated technique. It bridges dynamic polymorphism (object orientation) with static polymorphism (templates).<\/p>\n","protected":false},"author":21,"featured_media":6320,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[376],"tags":[420],"class_list":["post-6341","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-templates","tag-type-erasure"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6341","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=6341"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6341\/revisions"}],"predecessor-version":[{"id":6674,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/6341\/revisions\/6674"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/6320"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=6341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=6341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=6341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}