TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Type Erasure in C++ Explained

43 pointsby aptxkidabout 4 years ago

9 comments

einpoklumabout 4 years ago
That&#x27;s not how you do type erasure in C++.<p>Have a look at std::any : <a href="https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;any&#x2F;" rel="nofollow">https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;any&#x2F;</a><p>you can place a value of any type T in it (well, obviously it needs to be constructible etc.), or a std::nullopt, which is like an &quot;Empty&quot; or &quot;Nothing&quot; indicator that is not in T.<p>Then you can pass the `any` around without knowing its type. Finally, when you want to restore the typed value, you use any::get&lt;T&gt;(). It will succeed if T is the correct type, and throw an exception otherwise.<p>This was introduced into C++ in the C++17 version of the standard. Before, it existed as a Boost library facility.
评论 #26823178 未加载
AlexanderDhooreabout 4 years ago
&quot;Well, let&#x27;s just add another level of indirection.&quot;<p>Modern software development in a nutshell.
评论 #26823550 未加载
评论 #26823459 未加载
评论 #26824179 未加载
zackeesabout 4 years ago
This article is not a good explainer of type erasure because it uses inheritance to do it.<p>I’m waiting for the day that someone figures out and does a blog post showing that every std data structure can be rewritten with type erasure.<p>Here’s how it works:<p>Let’s use vector because it’s simple. This vector impl works with just plain void* memory with no type information.<p>The vector type wrapper (matching std::vector) is a template but instead of recreating the entire data structure with a different type, it will instead create the void* implementing vector in a unique_ptr and pass boiler plate functions so that the vector know how to: 1. the size of T 2. in place constructor of T at the void* 3. in place destructor of T at the void* 4. A copy constructor of T at void* src, dst.<p>The wrapper vector&lt;T&gt; that owns the vector impl then does the necessary casts back to T. For example vector::at could be implemented as such:<p><pre><code> &lt;template typename T&gt; class vector { &#x2F;&#x2F; type wrapper. T&amp; at(size_t i) { void* p = vector_impl_-&gt;get(i); T* t = static_cast&lt;T*&gt;(p); return *t; } ... } </code></pre> In this example, vector&lt;T&gt; wrapper would still be inlined everywhere, however VectorImpl could be defined exactly once in a cpp file. The template bloat problem is reduced from the entire data structure to just the wrapper casting back and forth from void* &lt;—&gt; T&amp;.<p>This can be extrapolated to complex algorithms like std::map. And as a bonus the polymorphic wrapper can do all the boiler plate generation so that the interface could be made to match the std::map.<p>Testing the bloat size reduction could be performed on a code base with significant usage of std map across multiple types, and see if the optimizing compiler will reduce the final binary size with the type erased map swapped in.
评论 #26824495 未加载
评论 #26825274 未加载
评论 #26830903 未加载
评论 #26824138 未加载
cobaltoxideabout 4 years ago
&gt; But the result is beautiful.<p>Uhhhh, gonna have to disagree there.
评论 #26824478 未加载
ok123456about 4 years ago
Wouldn&#x27;t this particular example be better served through C++2a concepts? That is we can specify constraints about template type parameters.
评论 #26824851 未加载
评论 #26823687 未加载
评论 #26823777 未加载
nyanpasu64about 4 years ago
I&#x27;m not sure whether Bar having a duck-typed constructor looking for the <i>presence</i> of a method is a good or bad idea, and I rather dislike how `Bar *` and `Bar &amp;` requires a double-indirection to call its contents. It feels inefficient, but I don&#x27;t know if it&#x27;s actually slower in practice, and I haven&#x27;t setup a benchmark to test. <a href="https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;cpp&#x2F;comments&#x2F;cs9ue4&#x2F;performance_benchmarks_of_type_erasure_methods&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;cpp&#x2F;comments&#x2F;cs9ue4&#x2F;performance_ben...</a> looks interesting but there&#x27;s a lot of data and I didn&#x27;t look at the source code of the various benchmark cases.
kazinatorabout 4 years ago
&gt; <i>But the result is beautiful.</i><p>Ugly as hell, ouch! Really?<p>GNU C++ had something called signatures years ago, which was removed. It was far more elegant.<p>You could declare a <i>signature</i> which was a class-like thing: function declarations in curly braces.<p>Having that signature declared, you could lift a pointer of that type to any object which had those functions (without any relationship to the signature having to be declared by that object).<p>Found a nice document on it:<p><a href="https:&#x2F;&#x2F;csc.lsu.edu&#x2F;~gb&#x2F;Signatures&#x2F;index.html" rel="nofollow">https:&#x2F;&#x2F;csc.lsu.edu&#x2F;~gb&#x2F;Signatures&#x2F;index.html</a><p>So, here is how the code would look:<p><pre><code> class Bar { &#x2F;&#x2F; nothing to inherit here public: void doSomething() { } }; signature Do { void doSomething(); }; void foo(Do &amp;doer) { doer.doSomething(); } int main() { Bar bar; foo(bar); } </code></pre> When <i>foo</i> is called with <i>bar</i>, a <i>Do &amp;</i> signature reference is taken to <i>bar</i>. This is allowed because the type Bar has all the functions declared in the signature type Do, making it compatible.<p>Sure, the implementation has to bend over backwards. But signatures are more declarative, so the implementation has a clearer idea of your intent. It can do whatever magic is required.<p>It seems clear to me that there is a static way to bind the Do signature reference to the Bar type. You probably have to construct some vtable like object which does the right sort of indirection.<p>The translation unit could emit some hidden __Do__Bar_table item which does exactly that: it&#x27;s a vtable-like table made in the shape of Do, which is filled with pointers (perhaps fat pointers with offsets and whatever is necessary) to the matching functions in Bar.<p>If that can be set up at compile time, then maybe the <i>Do &amp;doer</i> argument just has to be some sort of fat reference consisting of the pointer to <i>bar</i>, and to the __Do_Bar_table which translates the Do calls into Bar calls.<p>It seems cheaper than the convolution presented in this article.<p>Signatures didn&#x27;t make it into ISO C++, but since that time, a lot of cruft has which is worse.<p>Looks like this 1999 commit may be what removed signatures:<p><a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;git&#x2F;?p=gcc.git;a=commit;h=6eabb2412f6c4c8306fb2f8fd05abf608e29caa9" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;git&#x2F;?p=gcc.git;a=commit;h=6eabb2412f6c4c...</a><p>It doesn&#x27;t point to any information about the removal. We probably have to dig into mailing lists. At least it gives a date, thanks to which we can find this posting. Unfortunately, the one from which it quotes is missing for some reason:<p><a href="https:&#x2F;&#x2F;gcc.gnu.org&#x2F;pipermail&#x2F;gcc&#x2F;1999-August&#x2F;035433.html" rel="nofollow">https:&#x2F;&#x2F;gcc.gnu.org&#x2F;pipermail&#x2F;gcc&#x2F;1999-August&#x2F;035433.html</a><p>&quot;This patch removes support for `signature&#x27;, a g++ extension that is little-used and which Jason and I agreed should go. The reduction in complexity elsewhere in the front-end will be a big win.&quot;<p>OMG, you would absolutely not see this today in C++ development. &quot;Jason and I&quot; decided that some C++ gadget is too little used and we will remove it.<p>How naive that seems; these people had no idea about the deluge of garbage that was coming down the pipe into standard C++ over the following two decades, that they would have to implement.<p>They removed a good thing on a whim.
评论 #26825785 未加载
stephc_int13about 4 years ago
I am not sure this is an improvement.<p>What is the added value? What is the cost? Virtual methods are not free. Indirections are not free (when you read the code)
评论 #26824239 未加载
评论 #26823199 未加载
rambojazzabout 4 years ago
Wasn&#x27;t this called &quot;injection&quot;?