C++ Weekly - Episode 17 脱水版: C++17's `std::invoke`

35 阅读1分钟

C++ Weekly - Episode 17 脱水版: C++17's std::invoke

这一期主要讲了一个调用模板方法 std::invoke (C++17, C++20, C++23)。

cppreference: en.cppreference.com/w/cpp/utili…

从 C++ 17 开始, 标准库提供 std::invoke 可以调用普通函数, 成员函数, 函数指针, 还有 Lambda, 可调用对象等. 由于 cppreference 解释和例子复杂难懂, John 通过以下代码举了例子. 似乎更新了例子, 也很清晰, 这里作摘录 (怀疑官网的例子是不是 John 去更新的, 现在内容基本一致).

可以看到, std::invoke 各种可调用对象都实现了比较统一的调用方式, 甚至对于普通类成员可以.

John:

int do_something(const int i)
{
    return 5 + i;
}

struct S
{
    int j = 5;

    int do_something(const int i) {
        return j + i;
    }

    int do_something_2(const int i) {
        return j * i;
    }
};

int main()
{
    std::cout << std::invoke(&do_something, 5) << "\n";

    S s;
    std::cout << s.do_something(3) << '\n';

    auto fp = &S::do_something;
    int (S::*fp2)(int) = &S::do_something;

    int (S::*fp3)(int) = nullptr;
    if (true) {
        fp3 = &S::do_something;
    } else {
        fp3 = &S::do_something_2;
    }

    std::cout << (s.*fp)(2) << '\n';
    std::cout << (s.*fp2)(1) << '\n';

    //
    std::cout << std::invoke(&S::do_something,   s, 10) << '\n';
    std::cout << std::invoke(&S::do_something_2, s, 10) << '\n';    
    std::cout << std::invoke(fp2, s, 10) << '\n';
    
    std::cout << std::invoke(&S::j, s) << '\n';
}    

cppreference:

#include <functional>
#include <iostream>
#include <type_traits>
 
struct Foo
{
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};
 
void print_num(int i)
{
    std::cout << i << '\n';
}
 
struct PrintNum
{
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};
 
int main()
{
    // invoke a free function
    std::invoke(print_num, -9);
 
    // invoke a lambda
    std::invoke([]() { print_num(42); });
 
    // invoke a member function
    const Foo foo(314159);
    std::invoke(&Foo::print_add, foo, 1);
 
    // invoke (access) a data member
    std::cout << "num_: " << std::invoke(&Foo::num_, foo) << '\n';
 
    // invoke a function object
    std::invoke(PrintNum(), 18);
 
#   if defined(__cpp_lib_invoke_r)
    auto add = [](int x, int y) { return x + y; };
    auto ret = std::invoke_r<float>(add, 11, 22);
    static_assert(std::is_same<decltype(ret), float>());
    std::cout << ret << '\n';
    std::invoke_r<void>(print_num, 44);
#   endif
}