Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Suppose I wanted to write this entire system with staticly typed integrators.</p> <p>I would take your <code>on_integrateButton_clicked</code>, and change it to something like this:</p> <pre><code>void MainWindow::on_integrateButton_clicked() { string whichIntegrator = getUserChoice(); runInNewThread( [whichIntegrator,whichFunction,order]() { struct functor { FunctionType func; OrderType order; functor( FunctionType func_in, OrderType order_in):func(std::move(func_in)), order(std::move(order_in)) {} template&lt;typename Integrator&gt; void operator()( Integrator* integrator ) { // code using integrator here, not a virtual interface to it, an actual instance of the final type } }; RunWithChosenIntegrator( whichIntegrator, functor(whichFunction,order) ); } ); } </code></pre> <p>As you can see, the code seems a bit backwards.</p> <p>We defer the type selection as long as possible, and at that point we have it call a <code>functor</code> with a pointer to the integrator. This means that the code that uses the integrator has full type information of the integrator, and isn't dealing with it abstractly.</p> <p>Usually, runtime polymorphism or type erasure is sufficient for these kinds of problems, however.</p> <p>Now, <code>RunWithChosenIntegrator</code> is a bit of a strange beast. It would have a signature lookling like this:</p> <pre><code>template&lt;typename Functor&gt; void RunWithChosenIntegrator( std::string const&amp;whichIntegrator, Functor&amp;&amp; func ) { if (whichIntegrator == "bob") { BobIntegrator bob; func( &amp;bob ); } else if (whichIntegrator == "alice" ) { AliceIntegrator alice; func( &amp;alice ): } } </code></pre> <p>as you can see, we call <code>func</code> with a different type of object based on the <code>whichIntegrator</code> parameter. There are fun ways you can even generate the <code>if</code>/<code>else if</code> chains using metaprogramming, but that probably isn't worth learning until you are more comphy with basic template programming.</p> <p>The <code>Functor</code> <code>func</code> needs to be able to accept pointers to any and all of the types we call it with. A simple example might be a <code>func</code> that just takes a pointer to a base class, and the one I gave above takes a <code>T*</code> template type.</p> <p>All of this is only worth doing if either the overhead of runtime polymorphism is too high, or if you actually need to interact with the different integrator classes in non-uniform ways that is difficult or impossible to capture via runtime polymorphism.</p> <p>I doubt that this is the case here.</p>
 

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