Suppose I have a bar
and a foo
structures:
struct bar {
void bar_function() { }
};
struct foo {
bar* bar_ptr;
void foo_function() { }
};
Now, I'd like to call bar_function()
on each of foo
's bar_ptr
s from an std::vector
of foo
s:
std::vector<foo> fooVec;
ranges::for_each(
fooVec,
&bar::bar_function,
&foo::bar_ptr
);
This uses range-v3's projections - for each foo
, we take out bar_ptr
from it and then we call bar_function
on each of them.
I would assume that the above will work - we can, after all, std::invoke
a &bar::bar_function
with a pointer to a bar
(which we do have - the bar_ptr
). For the record I know that range-v3 uses std::invoke
magic to always do the right thing, so it surprises me that this fails with the following error:
error: no match for call to '(const ranges::for_each_fn) (std::vector<foo>&, void (bar::*)(), bar* foo::*)' [...] error: no class template named 'apply' in 'struct ranges::detail::enable_if<false>' 73 | using enable_if_t = typename enable_if<B>::template apply<T>; | ^~~~~~~~~~~ [...]
I'm not quite sure which part of the error is relevant here - I know that this fails the SFINAE tests, but I do not know why. Is there a reason why the above should fail or is it a bug?
Note that, if we replace &bar::bar_function
with [](auto bar_ptr) { bar_ptr->bar_function(); }
, the code happily compiles, which is weird, because, due to std::invoke
's nature (to "always do the right thing"), I fail to see the difference between those two:
std::invoke(&bar::bar_function, bar_ptr); // 1
std::invoke([](auto bar_ptr_arg) { // 2
bar_ptr_arg->bar_function();
}, bar_ptr);