Reputation: 75
I have the following snippet :
struct Foo {
Foo(int num):num_(num){}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int num_;
};
int main() {
std::vector<Foo*> vpf{ new Foo(3), new Foo(4), new Foo(5) };
auto pfa = std::mem_fn(&Foo::print_add);
int i = 42;
//std::for_each(vpf.begin(), vpf.end(), [&i](const auto& val){val -> print_add(i);});
std::for_each(vpf.begin(), vpf.end(), pfa(&i));
return 0;
}
Commented code that uses a lambda expression actually works as I expect printing 45, 46, 47. The uncommented code with std::for_each
that uses mem_fn
causes a compilation error attempt to use a deleted function
.
Can someone explain why and how I can properly use mem_fn
in this scenario?
Upvotes: 0
Views: 382
Reputation: 320747
I don't see how you could possibly obtain a "attempt to use a deleted function" error from this code. Either the code is inaccurate, or that diagnostic message is not the first one in the list.
The very first error in this code would refer to your pfa(&i)
subexpression, which is invalid. Firstly, in order to call pfa
you'd have to supply two arguments - of Foo *
and int
type - while you are supplying just one of int *
type. Secondly, in the context of std::for_each
you are not supposed to call pfa
yourself at all, you are supposed to pass pfa
itself to std::for_each
.
If you wanted to replace your lambda with something "lambdaless", e.g. using the "classic" std::mem_fn
functional object, it would look as follows
auto pfa = std::mem_fn(&Foo::print_add);
int i = 42;
std::for_each(vpf.begin(), vpf.end(), std::bind(pfa, std::placeholders::_1, i));
or, using the now-deprecated C++98 library features
auto pfa = std::mem_fun(&Foo::print_add);
int i = 42;
std::for_each(vpf.begin(), vpf.end(), std::bind2nd(pfa, i));
(Back then it was just... more fun somehow. More fun. Geddit? Ha ha ha... )
P.S. Note that (as @T.C. noted in the comments), there's no need to pre-wrap a member pointer through std::mem_fn
, if you are planning to use std::bind
on it. The first variant can be rewritten as
int i = 42;
std::for_each(vpf.begin(), vpf.end(),
std::bind(&Foo::print_add, std::placeholders::_1, i));
Upvotes: 1
Reputation: 16431
std::mem_fn
creates a functor that takes a reference or pointer to the type as the first parameter, and forwards the rest of its parameters to the actual function.
When passing it to an algorithm, you're not supposed to call it's ()
operator (you didn't do this for your lambda example). Your problem is that you also want to provide an argument to your function, and this simply isn't possible with just mem_fn
. You can do this with std::bind
or a lambda, though.
std::for_each(vpf.begin(), vpf.end(), std::bind(pfa, std::placeholders::_1, i));
or
std::for_each(vpf.begin(), vpf.end(), [&i,&pfa](const auto& val){ pfa(val, i); });
That being said, I think it's best to go with the lambda from your example. bind
is controvesial, and if you're using a lambda anyway, what's the point of adding mem_fn
to it?
Upvotes: 1
Reputation: 118435
auto pfa = std::mem_fn(&Foo::print_add);
&Foo::print_add
is not a function pointer. It is a class method pointer. You can't invoke it as a function pointer. You have to come up with an instance of the class for this method, and invoke the instance's method via the pointer.
std::for_each(vpf.begin(), vpf.end(), pfa(&i));
You are trying to invoke pfa
as if it was a function pointer it is not. First of all, std::for_each
passes the item in the sequence it iterates over, for each invocation. That's going to be the class instance you need to use with the method pointer:
std::for_each(vpf.begin(), vpf.end(),
[&i,&pfa](const auto& val){pfa(val, i);});
The lambda takes its parameter, the value in the sequence std::for_each
iterates over, and uses it to invoke the class method, via the method pointer. As expected, the resulting output from this is
45
46
47
Upvotes: 0