Reputation: 409
To start, I have something like this:
class Test {
std::vector<int> a, b;
void caller(...) { callee(...); }
void callee(...) { /* Do stuff with 'a' */ }
}
What I wanted is to have a function that does exactly the same as callee
but for vector b
. To do this there are two obvious solutions:
a
or b
as argument. However, callee
is a recursive function that can go for hundreds of calls, and passing the vectors as arguments would just be unnecessary overhead.callee
and use vector b
, which would be the best alternative, despite the fact that callee
is quite a long function and I would have a lot of duplicate code.Out of curiosity, I went looking for the templates part and I noticed that can be used for
lvalue reference type
pointer type
pointer to member type
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: use of ‘this’ in a constant expression
Is there any way to achieve this either with a reference or a pointer?
By the way, what I want can be seen as a function-scoped #define
Upvotes: 8
Views: 3356
Reputation: 63124
Arrays and even tuples, but no love for 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)` */ }
};
Upvotes: 9
Reputation: 2018
In the same logic as @Angew's answer, you could also use std::tuple, and it's quite interesting as with tuple you can also use different kind of containers in your callee 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
...
}
}
Upvotes: 1
Reputation: 171127
You cannot use a reference to a data member as a template argument: templates are compile-time, and the value of this
is not known until runtime. In other words, you'd need a separate instantiation (separate binary code) for each runtime object of type Test
.
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 instantiations of callee
(one for 0
and one for 1
), with the indexing done (or at least doable) at compile time.
Upvotes: 4
Reputation: 118330
Simply use a 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 in as one or the other class member.
Upvotes: 2