Note that there are some explanatory texts on larger screens.

plurals
  1. POContainer of Different Functors
    primarykey
    data
    text
    <p>I am trying to figure out a way to have a container of functors so that I can pass a value into the functors and have it be modified however I am having trouble allowing the functors to not be restricted in what types they can be passed and the amount of arguments they can take.</p> <p>My actual use for this is that I have a series of functors which all change a 3D vector in some way based on the input. By being able to store these functors in a container I can manipulate the order in which they are called in and end up with a different resulting vector by iterating over the container passing each functor the vector. I'm using these vectors to determine the position, colour, acceleration, etc. of a particle. So ultimately I can create vastly different particle effects by taking this modular approach and eventually I can have the functor order be defined by a file during runtime. That's my final goal :)</p> <p>The only way I have made this work is with inheritance and a bunch of void pointers which makes the code extremely hard to follow, debug and use.</p> <p>Here's my code so far that will hopefully demonstrate what I am trying to do better than what I have typed above. Please be aware I am highly out of my comfort zone so this code may be horrible and make some of you gurus want to beat me with a stick.</p> <pre><code>#include &lt;iostream&gt; #include &lt;vector&gt; //the base functor class struct Functor { //an integer so we can tell how many arguments the functor takes unsigned num_arguments; Functor() : num_arguments(0) {} //I'm making the arguments default to 0 so the compiler doesn't complain about not giving enough arguments virtual void operator()(void* R, void* A1 = 0, void* A2 = 0, void* A3 = 0) = 0; }; template&lt;typename R, typename A1&gt; struct Double : public Functor { Double() { num_arguments = 1; } void operator()(void* i, void* a, void*, void*) { //having to cast everything out of void pointers so it can be used A1&amp; first = *static_cast&lt;A1*&gt;(a); *static_cast&lt;R*&gt;(i) = first * 2; } }; template&lt;typename R, typename A1, typename A2&gt; struct Sub : public Functor { Sub() { num_arguments = 2; } void operator()(void* i, void* a, void* b, void*) { //having to cast everything out of void pointers so it can be used A1&amp; first = *static_cast&lt;A1*&gt;(a); A2&amp; second = *static_cast&lt;A2*&gt;(b); *static_cast&lt;R*&gt;(i) = first - second; } }; int main() { //our container for the functors std::vector&lt;Functor*&gt; functors; functors.push_back(new Double&lt;int, int&gt;); functors.push_back(new Sub&lt;int, int, int&gt;); for(int i = 0; i &lt; functors.size(); ++i) { int result; int first = 1, second = 2; Functor&amp; f = *functors[i]; if(f.num_arguments == 1) { f(&amp;result, &amp;first); } else if(f.num_arguments == 2){ f(&amp;result, &amp;first, &amp;second); } std::cout &lt;&lt; result &lt;&lt; std::endl; } Functor* float_sub = new Sub&lt;float, float, float&gt;; float result; float first = 0.5f, second = 2.0f; (*float_sub)(&amp;result, &amp;first, &amp;second); std::cout &lt;&lt; result &lt;&lt; std::endl; functors.push_back(float_sub); //The functors vector now contains 3 different types of functors: //One that doubles an integer //One that subtracts two integers //One that subtracts two floats std::cin.get(); return 0; } </code></pre> <p>Side note: I am expecting some people to tell me to use so-and-so from the boost libraries. Whilst I appreciate knowing that option is there I would still like to know a better way to implement this without any outside libraries as this is something of a learning exercise for myself.</p> <p><strong>Edit</strong></p> <p>Okay so having learnt of <code>stdarg</code> and <code>boost::any</code> I think I can see a way to make this work nicely and am trying it out :)</p> <hr> <h2>Solution 2</h2> <p>Okay I have reworked the code using the <code>boost::any</code> and <code>cstdarg</code> for what I think is a better solution. This doesn't use void pointers and doesn't restrict the amount of arguments the functors can have. The newer code also allows you to pass in by value, using void pointers everything had to be by reference which would cause problems trying to do: <code>Sub(&amp;result, 1, 1)</code></p> <pre><code>#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;cstdarg&gt; #include &lt;boost\any.hpp&gt; struct Functor { unsigned num_arguments; Functor() : num_arguments(0) {} virtual void operator()(boost::any, ...) = 0; }; template&lt;typename R, typename A1&gt; struct Double : public Functor { Double() { num_arguments = 1; } void operator()(boost::any r, ...) { R* out = boost::any_cast&lt;R*&gt;(r); va_list args; va_start(args, r); A1 first = va_arg(args, A1); va_end(args); *out = first * 2; } }; template&lt;typename R, typename A1, typename A2&gt; struct Sub : public Functor { Sub() { num_arguments = 2; } void operator()(boost::any r, ...) { R* out = boost::any_cast&lt;R*&gt;(r); va_list args; va_start(args, r); A1 first = va_arg(args, A1); A2 second = va_arg(args, A2); va_end(args); *out = first - second; } }; int main() { std::vector&lt;Functor*&gt; functors; functors.push_back(new Double&lt;int, int&gt;); functors.push_back(new Sub&lt;int, int, int&gt;); functors.push_back(new Sub&lt;int, float, float&gt;); int result = 0; for(int i = 0; i &lt; functors.size(); ++i) { (*functors[i])(&amp;result, 2, 2); std::cout &lt;&lt; result &lt;&lt; std::endl; } std::cin.get(); return 0; } </code></pre> <p>and now I finally have the privilege to upvote :D</p>
    singulars
    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