请考虑以下模板函数,它接受一个可调用对象、对其求值并返回结果(仅用于说明目的):
template<typename F, typename... A>
auto evaluate(F&& f, A&&... args) -> decltype(f(std::forward<A>(args)...))
{
return f(args...);
}
这适用于独立函数,但在传递成员函数时会中断,例如,其中 foo
是 Foo
的实例:
evaluate(&Foo::bar, foo, ...);
它提示无法调用成员函数:
error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f (...)’,
e.g. ‘(... ->* f) (...)’ auto evaluate(F&& f, A&&... args) -> decltype(f(std::forward<A>(args)...))
在 std::ref
中包装 f
确实允许传递成员函数:
template<typename F, typename... A>
auto evaluate(F&& f, A&&... args) -> decltype(std::ref(f)(std::forward<A>(args)...))
...
为什么会这样?
最佳答案
如果包装的对象是可调用的,则使 reference_wrapper 可调用的功能是将函数对象的引用传递到标准算法等的能力的基础。
这里我们创建了一个函数对象的引用元组:
int main()
{
struct A {
void operator()() const {
std::cout << "A\n";
}
};
struct B {
void operator()() const {
std::cout << "B\n";
}
};
A a;
B b;
auto ab = std::tie(a, b);
std::get<0>(ab)();
std::get<1>(ab)();
}
在这里,我们将对有状态函数对象的引用传递给标准算法:
struct EqualAndCount
{
EqualAndCount(char sought) : sought_(sought) {}
template<class R>
bool operator()(R const& r)
{
counter_++;
return sought_ == r;
}
std::size_t counter_ = 0;
char sought_;
};
int main()
{
EqualAndCount eq('j');
auto s = std::string("abcdefghijklmnop");
auto i = std::find_if(s.begin(), s.end(), std::ref(eq));
std::cout << "searched " << eq.counter_ << " chars";
if (i == s.end())
std::cout << " and did not find it\n";
else
std::cout << " and found it\n";
}
预期输出:
searched 10 chars and found it
Why does this work?
因为 std::reference_wrapper::operator()
是根据神话般的 INVOKE
(最高 c++14)和 编写的std::invoke
(c++17).
文档在这里:
关于c++ - 为什么可以使用 std::ref 将成员函数用作可调用类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39388239/