C ++: reference / pointer to member variable as template parameter

To get started, I have something like this:

class Test { std::vector<int> a, b; void caller(...) { callee(...); } void callee(...) { /* Do stuff with 'a' */ } } 

I would like to have a function that does the same thing as callee , but for vector b . There are two obvious solutions for this:

  • pass vector a or b as an argument. However, callee is a recursive function that can be used for hundreds of calls, and wrapping vectors as arguments is just an extra overhead.
  • Copy the callee function and use the vector b , which would be a better alternative, even though callee is a rather long function and I will have a lot of duplicate code.

Out of curiosity, I went to search for a part of the templates, and I noticed what can be used for

reference value type

pointer type

member type pointer

So I tried to do this:

 class Test { std::vector<int> a, b; void caller(...) { callee<a>(...); } template <std::vector<int> &x> void callee(...) { /* Do stuff with 'x' */ } } 

but i get

error: using 'this in constant expression

Is there a way to achieve this with either a link or a pointer?

By the way, what I want can be seen as a scope of #define functions

+6
source share
4 answers

Arrays and even tuples, but no love for the good old pointers to members?

 class Test { std::vector<int> a, b; void caller(/*...*/) { callee<&Test::a>(/*...*/); } template <std::vector<int> Test::*vec> void callee(/*...*/) { /* Do stuff with `(this->*vec)` */ } }; 
+4
source

You cannot use a link to a data element as an argument to a template: templates are compilation time, and the value of this unknown until execution. In other words, for each Test runtime object, you need a separate instance (separate binary code).

What you can do is replace a and b with an array and templatise callee by index into this array:

 class Test { std::array<std::vector<int>, 2> ab; void caller(...) { callee<0>(...); } template <size_t idx> void callee(...) { /* Do stuff with 'ab[idx]' */ } } 

This way you get only two instances of callee (one for 0 and one for 1 ), with indexing (or at least executable) at compile time.

+4
source

Just use the facade:

 class Test { std::vector<int> a, b; void caller_a(...) { callee(a); } void caller_b(...) { callee(b); } void callee(std::vector<int> &a_or_b, ...) { } } 

callee() will refer to its parameter, which will be passed as one or the other member of the class.

+2
source

In the same logic as @Angew's answer, you can also use std :: tuple, and this is quite interesting, since with a tuple you can also use different types of containers in your call function:

 class Test { std::tuple<std::vector<int>, std::list<int> > ab; void caller(...) { callee<0>(...); } template <size_t idx> void callee(...) { ... auto aIt = std::get<idx>(ab).begin(); // gets either the vector or the list depending on template value ... } } 
+1
source

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


All Articles