Reputation: 229461
This is a specific case of this question where that answer doesn't directly work.
struct hurg {};
class furg {
public:
template <class F>
void for_each_hurg(F&& f) const {
for (auto& h : hurgs) {
f(h);
}
}
template <class F>
void for_each_hurg(F&& f) {
for (auto& h : hurgs) {
f(h);
}
}
private:
std::vector<hurg> hurgs;
};
Usage:
furg f;
const auto& cf = f;
f.for_each_hurg([](hurg& h) { });
cf.for_each_hurg([](const hurg& h) { });
The code for the const
and non-const
versions is identical, but only because auto& h
infers const hurg&
in the first case and hurg&
in the second case.
In the spirit of the previously-linked-to Scott Meyers' solution, I came up with the following:
template <class F>
void for_each_hurg(F&& f) {
const_cast<const furg&>(*this).for_each_hurg([&f](const hurg& h) {
f(const_cast<hurg&>(h));
});
}
However, this seems like it could be more trouble than it's worth, especially if the types are long and if I can't use C++14's generic lambdas.
Upvotes: 1
Views: 172
Reputation: 39131
You can use a static member function template to forward *this
to a generic function parameter:
template<typename Self, typename F>
static void for_each_hurg(Self& s, F&& f) {
for (auto& h : s.hurgs) {
f(h);
}
}
template<typename F>
void for_each_hurg(F&& f) { for_each_hurg(*this, forward<F>(f))); }
template<typename F>
void for_each_hurg(F&& f) const { for_each_hurg(*this, forward<F>(f))); }
Since the advent of reference qualifiers for member functions, the general solution is to perfectly forward *this
. This doesn't always matter, since you often don't want member functions to be called on rvalues anyway. I'll add this here since I think it is part of a more general solution.
Unfortunately, *this
is always an lvalue, so you need additional manual care in the member function wrappers:
template<typename Self, typename F>
static void for_each_hurg(Self&& s, F&& f) {
/* ... */
}
template<typename F>
void for_each_hurg(F&& f) && { for_each_hurg(move(*this), forward<F>(f))); }
template<typename F>
void for_each_hurg(F&& f) & { for_each_hurg(*this, forward<F>(f))); }
Which is unfortunately not symmetric :(
It is also possible to implement the above via a friend function template. This can have two benefits:
furg
being a class template reduces the amount of function templates the compiler has to deal with (one per class template, instead of one per instantiation). This typically requires some boilerplate code and forward-declarations, though.furg f; for_each_hurg(furg, [](hurg){}); furg.for_each_hurg([](hurg){});
(When unqualified lookup finds a member function, it doesn't perform / ignores the results of ADL. Therefore, you'd have to put the friend function in namespace scope, in order to be able to refer to it via a qualified-id from within the non-static member function wrappers.)Additionally, you'd have to protect that function template from being to greedy; either by putting it into some namespace detail
or adding an enable-if clause. It's probably not worth the effort.
Upvotes: 3