如何解决函数指针真的是指针吗?还是物体?
我有一个疑问,因为起初我认为函数指针只是从字面上读取的普通指针。但是后来我发现了一些线索,表明它看起来不像普通的指针,但更像是一个对象。
来自 C ++ Primer 5th (重点是我):
当我们定义lambda时,编译器会生成一个新的(未命名)类 对应于该lambda的类型。我们将看看这些课程如何 §14.8.1(第572页)中生成。现在,了解什么有用 是当我们将lambda传递给函数时,我们同时定义了 新类型和该类型的对象:参数是未命名的对象 这种由编译器生成的类类型。 类似地,当我们使用
auto
定义一个由lambda初始化的变量,我们正在定义一个对象 从该lambda生成的类型。
这表示auto
实际上定义了对象。 (并不是说它是在定义指向对象的指针)
和
auto z = [](int i) -> int { return i + 3; };
int(*z2)(int) = [](int i) -> int { return i + 3; };
进行编译,所以我认为z
的类型是函数指针int(*z2)(int)
。
所以我基于这些推论是:
auto
定义了一个对象,并且z
的类型是函数指针int(*z2)(int)
,因此函数指针实际上是对象类型,而不是对象类型普通指针。
我发现的另一个线索是:
考虑一下我编写的此代码段,以将lambda与具有operator()
的对象进行比较。
#include <iostream>
using namespace std;
int(*f1()) (int) {
return [](int i) -> int {
return i + 3;
};
}
struct Foo {
int operator()(int i) const {
return i + 3;
}
};
Foo f2() {
return Foo();
}
Foo* f3() {
return new Foo();
}
int main() {
int(*q)(int) = f1();
cout << q(1) << endl;
Foo m = f2();
cout << m(1) << endl;
Foo* m2 = f3();
cout << (*m2)(1) << endl;
delete m2;
return 0;
}
如果q
实际上是一个函数指针,则它应该像m2
一样指向Foo
的指针,并且需要delete
。并且返回lambda就像返回new Foo()
(类似于函数f3
一样工作),或者lambda无法使调用函数失效。
但是事实是q
不需要delete
。
所以现在我想q
实际上是一个对象,那么一切都说得通。就像m
一样工作,返回lambda就像返回Foo()
(就像函数f2
一样工作)。
那么,我的猜测正确吗?
解决方法
如您引用的文本中所述,lambda等效于定义了struct
的{{1}}。您的第二个程序非常类似于:
operator()
仅当lambda没有捕获任何东西时,才存在向自由函数指针的转换,显然,如果int the_function(int i) { return i + 3; }
struct foo
{
int operator()(int i) { return the_function(i); }
using Ftype = int(int);
operator Ftype *() { return the_function; }
};
auto f1() -> int(*)(int) { return foo(); }
auto f2() -> foo { return foo(); }
auto f3() -> foo* { return new foo; }
int main()
{
int (*q)(int) = f1();
q();
foo m = f2();
m();
foo* m2 = f3();
delete m2;
}
具有foo
需要访问的成员变量,这将是不可能的。
调用the_function
很好,因为q();
在程序的生存期内一直存在,因此是否存在任何lambda对象都没有关系。
C风格的函数指针与其他任何指针一样,除了一个指针可以运行它所指向的代码(并且指针算术不起作用)。如您所提到的,仅当lambda不包含任何捕获时,才可以将其分配给函数指针。并且只有这样才能衰减到函数指针。但是,捕获会创建一个包含数据和代码的对象。这将使其与C样式函数指针不兼容。
,您需要区分:
-
像
void (*foo)(int,double);
这样的函数指针实际上只是底层的一个地址,指向可执行代码的第一个字节。 (至少在X86上,其他平台可能以不同的方式实现它们。) -
lambda不是函数指针。这是一个类型无法确定的对象,只能通过模板参数和
auto
变量来传递。
可以将某些lambda(无捕获的lambda)隐式转换为函数指针,使您可以将其传递给需要函数指针的函数。但是,这是一次真正的转换,结果指针与您放入的lambda并不相同。到目前为止,您甚至无法撤消转换。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。