Can I do this using a template class in C ++

I have a class similar to this:

int add(int a,int b) { return a+b; } int sub(int a,int b) { return ab; } class C { int m_functionType; C(int functionType) { m_functionType=functionType; } int calc(int a, int b) { switch(m_functionType) { case 1: // add return add(a,b); break; case 2: // subtract return sub(a,b); } } }; 

and use it as follows:

 main() { C add(1); C sub(2); auto x=add.calc(1,2); auto z=sub.calc(2,1); } 

This code works, but the function that needs to be called is allowed at runtime, I am looking for a solution that solves the functions to be called at compile time. something like that:

 template <int func> class C { int calc(int a, int b) { switch(func) { case 1: // add return add(a,b); break; case 2: // subtract return sub(a,b); } } }; main() { C<1> add; C<2> sub; auto x=add.calc(1,2); auto z=sub.calc(2,1); } 

Is the above code actually resolving a function at compile time or still resolving it at runtime?

Is there a way I can do this using the template class? Assuming I want to compile it on Visual studio 2013 and GNU, which have some C ++ 11 features.

+6
source share
3 answers

In your example, func resolves at runtime in main :

 C add(1); C sub(2); 

Compilation time will mean:

 C<1> add; C<2> sub; 

If the change above is acceptable, the classic C ++ 98/03 idea is to use function overloads:

 template <int v> struct IntToType { enum {val = v}; }; int calc_impl(a, b, IntToType<1>) { return add(a, b); } int calc_impl(a, b, IntToType<2>) { return sub(a, b); } template <int func> class C { int calc(int a, int b) { return calc_impl(a, b, IntToType<func>()); } }; 

Notes:

  • calc_impl are just two functions containing three arguments. The name of the third argument is omitted because it is not used. They are overloaded with the third parameter, because IntToType<1> and IntToType<2> are two different types.
  • You can put calc_impl functions in a private section of your class for better ergonomics.
+7
source

From the views of things, you really want to pass an action that should be called as a template parameter to an external function that calls an indirect call. Depending on your point of view, this can be thought of as a policy class or as an instance of strategy template 1 .

Since templates are mostly type-based, you usually want to do this with classes, not functions. Other than that, it's quite simple, although there are several different possible approaches.

One approach would be to force calc to invoke the specified policy in response to its called operator() . The code for this will look like this:

 #include <iostream> struct add { int operator()(int a, int b) { return a + b; } }; struct sub { int operator()(int a, int b) { return a - b; } }; template <class C> struct calc { int operator()(int a, int b) { return C()(a, b); } }; 

The code to use might look something like this:

 int main() { auto x=calc<add>()(1,2); auto z=calc<sub>()(2,1); } 

Another possibility would be for calc perform the calculation when building the object and return the result on request. This avoids (among other things) an additional set of partners for creating the object, and then call its operator() to perform the calculation. On the other hand, this means adding an implicit conversion operator from the calculation object to return the result of the calculation, which many people don't like. The code following this route may look like this:

 template<class C> struct calc2 { int val; public: calc2(int a, int b) : val(C()(a, b)) {} operator int() { return val; } }; // ... std::cout << calc2<add>(1, 2) << "\n"; std::cout << calc2<sub>(2, 1) << "\n"; 

Itโ€™s a little difficult to say what is really preferable between these two options (and there are other options). Between them, the choice is mainly between an ugly challenge and an ugly implicit transformation.

Of course, depending on what you do in the โ€œstrategicโ€ part of things, the solution may be simple: if you really need to perform the action only on demand, and not immediately after creation (and save only the result until it is needed ), the second option is not an option at all.

I must add that I assume that the integer that you are currently using to determine which operation should be used was a random side effect of the implementation that you figured out. In other words, I assume that specifying the operation itself directly, as I did above, is really preferable.


<sub> 1. Strategy is usually a whole algorithm, and not something as trivial as adding versus subtraction, but I assume that only an example, and your real application does something more significant. Sub>

0
source

Which function is called is allowed at compile time, because any semi-decent modern compiler can optimize unused cases from your switch .

-1
source

Source: https://habr.com/ru/post/985802/


All Articles