函数指针是 C++ 中的函数对象吗?

Are function pointers function objects in C++?

C++ 标准将函数对象定义为:

A function object type is an object type that can be the type of the postfix-expression in a function call. (link)

起初我以为函数对象是仿函数,但后来我意识到对于类型为P的函数指针ptr(不是函数,而是函数指针),std::is_object_v<P>true 并且可以用 ptr(Args...) 语法调用。

函数指针被标准视为函数对象,我说得对吗?如果它们不是函数指针不满足定义的哪一部分?

是的,他们是。 C++ 标准中的术语 "object" 并不意味着 OOP 意义上的 "object"。 int 是一个对象。

函数指针顾名思义:指向函数的指针。它本身是一个包含指针对象的存储,returns 函数类型的可调用对象。

如果您花时间阅读标准的第一章,您就会明白任何变量声明都声明了某种包含 对象 的存储类型。这些可以是原始类型或 classes 的对象。本质上 在 C++ 中,任何可以存储的东西都是对象

通过声明函数指针,您创建的存储可以存储该函数的地址,并且可以使用 operator()

Lambda 表达式可以创建另一种类型的可调用闭包。它们不是函数对象,每个表达式创建一个唯一的可调用对象,但无捕获的 lambda 可以作为一个对象使用,例如将其分配给函数指针,例如

double (*square)(double) = [](double a)->double { return a*a; };

在此之后你可以使用像 square(3.6);

这样的表达式来调用它

对于函数和 lambda 调用运算符 operator() 是由语言提供的,通过为 class 定义 operator() 你创建了人们通常所说的 "functor",这是用词不当因为数学或 Haskell 等语言中的实际仿函数不 存储状态。 lambda 表达式的结果是由编译器创建的 "functor",它存储捕获对象的状态。

将这些对象命名为可调用对象也可能有点误导,因为作为 C++ 中的一个概念,可调用对象是任何可以与 INVOKE 操作一起使用的对象,它包括指向数据成员的指针,即使没有函数调用发生。

它只留下一个选项,如果我们可以对所述对象使用函数调用,它就是一个函数对象。它可以是函数、lambda 表达式、函数对象、函数指针、具有指定 class 实例的成员函数指针(obj.*memberptrobjptr->*memberptr - 成员函数的调用非常特殊) - 它们是函数对象。

函数指针是函数对象,但它们也有一个来自C时代的有趣怪癖:

#include <iostream>

int foo(int a)
{
    std::cout << "Hello, " << a << " stars\n";
    return a;
}
    
int (*pr) (int) = foo;

int main()
{
    pr(0);
    (*pr)(1);
    (**pr)(2);
    (***pr)(3);
    return 0;
}

后缀表达式应具有函数类型或指向函数类型的指针,并且函数在需要此类转换时可根据上下文转换为函数指针,因此重复取消引用运算符会“来回”弹回类型,使其成为函数指针. Captureless lambda 也可以:

// also can write `auto pr2 = ...`
int (*pr2) (int) = [](int a)->int { 
         std::cout << "Hello, lambda " << a <<  " stars\n"; return a; 
};

// in main()
(**pr2)(2);

自然地,如果 pr 是广义的“仿函数”,则该代码格式错误

int b = 2;
auto pr3 = [=]()->int { 
   std::cout << "Hello, general lambda " << b << std::endl; 
   return b; 
};

pr3();
//(*pr3)();  Ill-formed: not a pointer!