c++ - 为什么可以使用 std::ref 将成员函数用作可调用类型?

标签 c++ c++11

请考虑以下模板函数,它接受一个可调用对象、对其求值并返回结果(仅用于说明目的):

template<typename F, typename... A>
auto evaluate(F&& f, A&&... args) -> decltype(f(std::forward<A>(args)...))
{
  return f(args...);
}

这适用于独立函数,但在传递成员函数时会中断,例如,其中 fooFoo 的实例:

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).

文档在这里:

http://en.cppreference.com/w/cpp/utility/functional/invoke

关于c++ - 为什么可以使用 std::ref 将成员函数用作可调用类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39388239/

相关文章:

c++ - 未在部分特化中使用的模板参数

c++ - placement new 基于模板 sizeof()

c++ - 如何创建一个新线程并在一段时间后终止它?

c++ - stringstream 无符号输入验证

c++ - 当数组作为调用函数中的参数传递时,为什么不能在被调用函数中使用 foreach 循环打印数组的值?

c++ - 什么是函数的引用限定符?

c++ - 在基于 Trident 的应用程序中调试 JavaScript

c++ - std::numeric_limits 作为条件

c++ - 了解临时对象上下文中的函数调用

c++ - 为什么 Google Test/Mock 通过 std::unique_ptr 显示泄露的模拟对象错误?