Note that there are some explanatory texts on larger screens.

plurals
  1. POType erasure techniques
    primarykey
    data
    text
    <p><sup>(With type erasure, I mean hiding some or all of the type information regarding a class, somewhat like <a href="http://www.boost.org/doc/libs/1_46_0/doc/html/any.html" rel="noreferrer">Boost.Any</a>.)</sup><br> I want to get a hold of type erasure techniques, while also sharing those, which I know of. My hope is kinda to find some crazy technique that somebody thought of in his/her darkest hour. :) </p> <p>The first and most obvious, and commonly taken approach, that I know, are virtual functions. Just hide the implementation of your class inside an interface based class hierarchy. Many Boost libraries do this, for example <a href="http://www.boost.org/doc/libs/1_46_0/doc/html/any.html" rel="noreferrer">Boost.Any</a> does this to hide your type and <a href="http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/shared_ptr.htm" rel="noreferrer">Boost.Shared_ptr</a> does this to hide the (de)allocation mechanic. </p> <p>Then there is the option with function pointers to templated functions, while holding the actual object in a <code>void*</code> pointer, like <a href="http://www.boost.org/doc/libs/1_46_1/doc/html/function.html" rel="noreferrer">Boost.Function</a> does to hide the real type of the functor. Example implementations can be found at the end of the question.</p> <p>So, for my actual question:<br> What other type erasure techniques do you know of? Please provide them, if possible, with an example code, use cases, your experience with them and maybe links for further reading.</p> <p><strong>Edit</strong><br> (Since I wasn't sure wether to add this as an answer, or just edit the question, I'll just do the safer one.)<br> Another nice technique to hide the actual type of something <strong>without</strong> virtual functions or <code>void*</code> fiddling, is the one GMan employs <a href="https://stackoverflow.com/questions/2552839/which-c-standard-library-wrapper-functions-do-you-use/2553109#2553109">here</a>, with relevance to <a href="https://stackoverflow.com/questions/4985800/why-is-the-derived-classs-destructor-invoked-on-a-const-reference-to-the-base-cl">my question</a> on how exactly this works.</p> <hr> <p>Example code:</p> <pre><code>#include &lt;iostream&gt; #include &lt;string&gt; // NOTE: The class name indicates the underlying type erasure technique // this behaves like the Boost.Any type w.r.t. implementation details class Any_Virtual{ struct holder_base{ virtual ~holder_base(){} virtual holder_base* clone() const = 0; }; template&lt;class T&gt; struct holder : holder_base{ holder() : held_() {} holder(T const&amp; t) : held_(t) {} virtual ~holder(){ } virtual holder_base* clone() const { return new holder&lt;T&gt;(*this); } T held_; }; public: Any_Virtual() : storage_(0) {} Any_Virtual(Any_Virtual const&amp; other) : storage_(other.storage_-&gt;clone()) {} template&lt;class T&gt; Any_Virtual(T const&amp; t) : storage_(new holder&lt;T&gt;(t)) {} ~Any_Virtual(){ Clear(); } Any_Virtual&amp; operator=(Any_Virtual const&amp; other){ Clear(); storage_ = other.storage_-&gt;clone(); return *this; } template&lt;class T&gt; Any_Virtual&amp; operator=(T const&amp; t){ Clear(); storage_ = new holder&lt;T&gt;(t); return *this; } void Clear(){ if(storage_) delete storage_; } template&lt;class T&gt; T&amp; As(){ return static_cast&lt;holder&lt;T&gt;*&gt;(storage_)-&gt;held_; } private: holder_base* storage_; }; // the following demonstrates the use of void pointers // and function pointers to templated operate functions // to safely hide the type enum Operation{ CopyTag, DeleteTag }; template&lt;class T&gt; void Operate(void*const&amp; in, void*&amp; out, Operation op){ switch(op){ case CopyTag: out = new T(*static_cast&lt;T*&gt;(in)); return; case DeleteTag: delete static_cast&lt;T*&gt;(out); } } class Any_VoidPtr{ public: Any_VoidPtr() : object_(0) , operate_(0) {} Any_VoidPtr(Any_VoidPtr const&amp; other) : object_(0) , operate_(other.operate_) { if(other.object_) operate_(other.object_, object_, CopyTag); } template&lt;class T&gt; Any_VoidPtr(T const&amp; t) : object_(new T(t)) , operate_(&amp;Operate&lt;T&gt;) {} ~Any_VoidPtr(){ Clear(); } Any_VoidPtr&amp; operator=(Any_VoidPtr const&amp; other){ Clear(); operate_ = other.operate_; operate_(other.object_, object_, CopyTag); return *this; } template&lt;class T&gt; Any_VoidPtr&amp; operator=(T const&amp; t){ Clear(); object_ = new T(t); operate_ = &amp;Operate&lt;T&gt;; return *this; } void Clear(){ if(object_) operate_(0,object_,DeleteTag); object_ = 0; } template&lt;class T&gt; T&amp; As(){ return *static_cast&lt;T*&gt;(object_); } private: typedef void (*OperateFunc)(void*const&amp;,void*&amp;,Operation); void* object_; OperateFunc operate_; }; int main(){ Any_Virtual a = 6; std::cout &lt;&lt; a.As&lt;int&gt;() &lt;&lt; std::endl; a = std::string("oh hi!"); std::cout &lt;&lt; a.As&lt;std::string&gt;() &lt;&lt; std::endl; Any_Virtual av2 = a; Any_VoidPtr a2 = 42; std::cout &lt;&lt; a2.As&lt;int&gt;() &lt;&lt; std::endl; Any_VoidPtr a3 = a.As&lt;std::string&gt;(); a2 = a3; a2.As&lt;std::string&gt;() += " - again!"; std::cout &lt;&lt; "a2: " &lt;&lt; a2.As&lt;std::string&gt;() &lt;&lt; std::endl; std::cout &lt;&lt; "a3: " &lt;&lt; a3.As&lt;std::string&gt;() &lt;&lt; std::endl; a3 = a; a3.As&lt;Any_Virtual&gt;().As&lt;std::string&gt;() += " - and yet again!!"; std::cout &lt;&lt; "a: " &lt;&lt; a.As&lt;std::string&gt;() &lt;&lt; std::endl; std::cout &lt;&lt; "a3-&gt;a: " &lt;&lt; a3.As&lt;Any_Virtual&gt;().As&lt;std::string&gt;() &lt;&lt; std::endl; std::cin.get(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload