You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C++可调用类型分类及std::invoke首参可接受类型咨询

C++可调用类型与std::invoke参数详解

嘿,我来帮你理清这些C++里的可调用类型和std::invoke的参数问题~

一、C++中的可调用类型

在C++里,只要是能通过()运算符(或配合对象实例)完成调用的类型,都属于可调用类型,具体包括:

  • 普通函数(全局函数、命名空间内的函数都算)
  • 函数指针(指向普通函数、静态成员函数的指针)
  • 函数引用(对普通函数的引用)
  • 非静态成员函数指针(注意这类指针调用时必须搭配类的对象实例)
  • 非静态成员函数引用
  • 仿函数(重载了operator()的类/结构体的实例,比如std::function就是典型的包装类仿函数)
  • Lambda表达式(本质是编译器生成的匿名仿函数实例,不管有没有捕获变量都算)
  • std::bind返回的绑定表达式对象
  • 类的静态成员函数(可以当作普通函数指针来使用)
  • 自定义可调用对象(只要重载了合适的operator()就行,比如某些智能指针包装的对象)

二、std::invoke可接受的第一个参数类型(满足std::is_invokable_v<F, Args...>为true的F)

std::invoke的设计就是统一处理各种可调用类型的调用,所以所有上面提到的可调用类型,只要搭配合适的Args参数,都可以作为它的第一个参数。我们可以按类型层级梳理:

1. 基础函数相关类型

  • 普通函数本身:直接传函数名就能调用,比如std::invoke(my_func, arg1, arg2);
  • 函数指针:不管是指向普通函数还是静态成员函数的指针都没问题,比如:
    void (*fp)() = &my_func;
    std::invoke(fp);
    
  • 函数引用:用法和函数指针类似,比如:
    void (&fr)() = my_func;
    std::invoke(fr);
    

2. 类成员相关类型

这是std::invoke特别处理的场景,普通的函数调用语法没法直接用成员指针,但invoke可以:

  • 非静态成员函数指针:需要在Args里传入类的对象实例(可以是对象本身、指针或者引用),比如:
    std::invoke(&MyClass::my_method, obj_instance, arg);
    std::invoke(&MyClass::my_method, &obj_instance, arg); // 传指针也可以
    
  • 非静态数据成员指针:这时候invoke会返回该成员的值,同样需要传入对象实例,比如:
    std::invoke(&MyClass::my_member, obj_instance);
    

3. 用户自定义可调用对象

这类类型的灵活性最高,只要符合可调用规则就行:

  • 仿函数实例:比如自定义的结构体重载operator()后,直接传实例即可:
    struct Foo {
        void operator()() { /* do something */ }
    };
    Foo foo;
    std::invoke(foo);
    
  • Lambda表达式:直接传Lambda实例,捕获变量的Lambda也完全支持:
    int x = 10;
    std::invoke([x](){ std::cout << x << std::endl; });
    
  • std::function包装对象:作为可调用类型的通用包装,自然可以被invoke处理:
    std::function<int(int)> f = [](int a){ return a*2; };
    std::invoke(f, 5); // 返回10
    
  • std::bind返回的绑定对象:绑定后的参数可以直接通过invoke触发调用:
    auto bound_func = std::bind(my_func, arg1, std::placeholders::_1);
    std::invoke(bound_func, arg2);
    

简单来说,std::is_invokable_v<F, Args...>为true的核心就是:给定F和Args,std::invoke(F, Args...)是合法的C++代码。所以所有能被invoke合法调用的类型,都满足这个条件。

内容的提问来源于stack exchange,提问作者Vincent

火山引擎 最新活动