为什么将函数分配给 std::function 会导致未定义的引用?

Why assigning a function to a `std::function` cause undefined reference?

#include <functional>

int foo(size_t);
std::string bar(size_t);

int main() {
  std::function<void(size_t)> f;
  f = foo;
  f = bar;
  return 0;
}

在上面的代码片段中,我试图将两个函数 foobar 分配给一个 std::function,这两个函数是这样声明的。我还没有调用函数,为什么会导致链接器错误?

/tmp/ccQwGxWs.o: In function `main':
functionCompatibleTypes.cpp:(.text+0x2b): undefined reference to `foo(unsigned long)'
functionCompatibleTypes.cpp:(.text+0x41): undefined reference to `bar[abi:cxx11](unsigned long)'
collect2: error: ld returned 1 exit status

缺少函数的实现,这就是找不到参考的原因。

尝试:

#include <functional>

int foo(size_t){};
std::string bar(size_t){};

int main() {
  std::function<void(size_t)> f;
  f = foo;
  f = bar;
  return 0;
}

创建指向函数的指针需要函数的地址。编译器不知道函数的地址,因此它插入了一个符号引用,链接器稍后会尝试修复它。

请务必记住,链接发生在优化之后。因此,如果优化器删除了对某个函数的所有引用,那么链接器就不会抱怨。

现在你可能会问为什么编译器没有优化掉函数指针?

我怀疑答案是 std::function 并不简单,它在幕后做了很多工作来支持任意可调用类型。这通常通过为分配给 std::function 的每种类型生成调用者和管理器函数来实现。指向调用者和管理器函数的指针存储在 std::function 中,当调用者或管理器函数被调用时,它被传递一个指针或引用(不确定是哪个,这并不重要)到 std::function.必须调用管理器函数作为重新分配和销毁 std::function.

的一部分

一个足够积极的优化器可以取消选择它,但这绝对是不平凡的,并且不能保证每个优化器都会这样做。为了优化代码,编译器必须首先内联构造函数、赋值运算符和析构函数调用,然后发现通过直接调用管理器函数的函数指针替换调用是安全的,然后将调用内联到管理器函数,只有这样,优化器才能看到指向 foo 和 bar 的指针实际上从未被使用过。

编辑:刚刚在 godbolt 上用编译器测试了这个,O2 和更高版本的 clang 似乎成功地优化了对 foo 和 bar 的引用,但 gcc 没有在任何优化级别。

函数声明后没有实现,compilation.If你使用函数指针后没有得到函数的地址,编译器会认为你很可能是要调用函数,所以你必须提供实现