Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The two existing solutions trade dynamic polymorphism for static polymorphism. Without more details on the problem at hand, it is not possible to know whether that is a valid approach or not, as it basically breaks the polymorphic hierarchy: with CRTP there is no single base class, but rather a family of them. You cannot hold objects of <code>Derived1</code> and <code>Derived2</code> in the same container as they are unrelated... It is a fine solution if all you need is to share the code, but not if you need dynamic polymorphism. Take a look at the Visitor pattern and at double-dispatch for similar problems.</p> <p>If you need dynamic polymorphism, you could try to implement double dispatch (it is a pain, but feasible if the hierarchy is small enough. Basically create two different hierarchies, one rooted at <code>Base</code> and another that serves as some short of manual dispatcher. The hierarchy rooted at <code>Base</code> will have a virtual method <code>apply</code>, and the second hierarchy will have virtual functions for each one of the types in the first hierarchy:</p> <pre><code>class Base; class Derived1; // inherits from Base, implements Visitor class Derived2; // inherits from either Base or Derived2 struct Visitor { virtual void visit( Base&amp; ) = 0; // manually unrolled for all types virtual void visit( Derived1&amp; ) = 0; virtual void visit( Derived2&amp; ) = 0; }; struct Base { virtual void apply( Visitor&amp; v ) { // manually replicate this in Derived1, 2 v.visit( *this ); } template &lt;typename T&gt; void foo(T); // implement }; template &lt;typename T&gt; struct FooCaller : Visitor { T&amp; ref_value; FooCaller( T&amp; v ) : ref_value(v) {} template &lt;typename U&gt; void call_foo( U&amp; o ) { o.foo(ref_value); } virtual void visit( Base &amp; b ) { call_foo(b); } virtual void visit( Derived1 &amp; d1 ) { call_foo(d1); } virtual void visit( Derived2 &amp; d2 ) { call_foo(d2); } }; </code></pre> <p>The names I have used are common in the Visitor pattern, and this approach is quite similar to that pattern (I don't dare call it the Visitor pattern, but the approach is similar, so I just borrowed the naming convention).</p> <p>User code would be similar to:</p> <pre><code>int main() // main returns int, not void!!! { Base* BasePtr = new Derived1(); int i = 5; FooCaller&lt;int&gt; c(i) BasePtr-&gt;apply(c); // [1] magic happens here } </code></pre> <p>The requirement of declaring <code>i</code> and <code>c</code> before hand can be released by changing (if possible) the arguments to the functions from references to const-references. The actual magic is that in [1] the C++ single dispatch mechanism sill dispatch the call to <code>Derived1::apply</code>, since that is the dynamic type of the object pointed by <code>BasePtr</code>. At that point it will call <code>Visitor::visit( Derived1&amp; )</code> with itself as the argument. That will again be dispatched through the single dispatch mechanism to <code>FooCaller&lt;int&gt;::visit( Derived1&amp; )</code>, and at that point both objects have been resolved to their static types. When <code>FooCaller&lt;int&gt;::visit</code> calls <code>call_foo</code> the argument <code>U</code> is deduced to be <code>Derived1</code>, when it calls <code>Derived1::foo</code> the argument is deduced to be <code>int</code> and it ends up calling <code>Derived1::foo&lt;int&gt;</code>... though a couple of loops and indirections...</p> <p>Depending on your particular use case this might be too complex (if static polymorphism like CRTP would work) or too hard to maintain (if the hierarchy is big: for each new element in the <code>Base</code> hierarchy you will have to update <em>all</em> types in the hierarchy of the <code>Visitor</code>), so if you can avoid this complexity, perfect. In some cases, though, you need this.</p> <p>Also note that this is the most complex fully dynamic solution, there are other options in between, depending on what is it that you need to be runtime polymorphism... It might be the case that your hierarchy models a visitor of shorts, and that you only need to manually unroll the different virtual functions that will dispatch to the template internally, in which case half of the above complexity will be gone.</p> <p>Also note that this is quite unusual in C++, and that if you explain the actual problem at hand, there might be better simpler solutions, what you have stated are the requirements of your solution to the original problem: dynamically dispatch to a template.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      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