1

我的问题涉及在 C++ 中对函数包装器应用内联优化,考虑以下代码,WorkerStructure 对象是使用封装了一些功能块的函数包装器初始化的。然后在调用 WorkerStructure::doSomeWork 方法时使用函数包装器。

workerFunction 对象封装的功能在应用于 WorkerStructure::doSomeWork 方法时会被内联吗?显然如果功能是在其他翻译单元中定义的,workerFunction 对象只封装了一个函数指针,是否还有其他情况可以内联?不可能吗?

当通过函数包装器传递在不同翻译单元中定义的 lambda 函数时,它实际上等效于传递函数指针吗?

struct WorkerStructure
{
    WorkerStructure(std::function <bool(float)> &f):workerFunction(f) {}

    void doSomeWork(float inputValue)
    {
        if(workerFunction(inputValue))
        {
            //do some conditional operation
        }
    }
    std::function <bool(float)> workerFunction ;
};
4

2 回答 2

5

固有的多态性std::function使得实际内联调用变得非常非常困难。由于std::function可以故事任何可调用的实体;您将如何编写内联代码?

这有点像内联虚函数,通过基指针调用而没有其他可用信息(也就是在调用之前没有从派生到基指针的赋值,编译器可能会使用它来启用内联)。

大多数时候,std::function是用一个void*指针和一个函数指针来实现的,该指针指向模板化函数的特化,它执行实际的调用和强制转换等。当然有一些变体使用虚函数来做到这一点,而且它们更清楚为什么它非常困难。即使是链接时优化也无法做任何事情,因为没关系,您已经拥有了可以在呼叫站点获得的所有信息(这并不多)。

这是使用指向模板函数版本的指针的一个非常粗略的版本,仅处理存储和调用方面(省略内存管理、复制、移动、重置、空间优化等):std::function

template<class Sig>
class function;

template<class R, class... Args>
class function<R(Args...)>{
  typedef R (*call_type)(void*, Args...);
  void* _obj;
  call_type _caller;

public:
  template<class F>
  function(F f)
    : _obj(new F(f))
    , _caller([](void* p, Args... args){ return (*static_cast<F*>(p))(args...); })
  {}

  R operator()(Args... args) const{
    return _caller(_obj, args...);
  }
};

活生生的例子。我认为很难检查其中的实际内容_obj以及调用_caller的点。function

仅供参考,这里是带虚函数的版本

于 2012-09-29T16:47:15.627 回答
1

有趣的是,我今天刚刚在邮件列表中询问了有关 Clang/LLVM 中的虚函数内联的问题。的动态特性std::function使其本质上是一个虚拟调用,因为virtual调用只不过是指向函数的指针。

以 LLVM 为例,让我们玩一下下面的程序:

#include <cstdio>

typedef void (*Function)();

void donothing() {}
void print() { printf("Hello World!"); }

Function get(int i) {
    if (i % 2 == 0) { return donothing; }
    return print;
}

int main() {
    Function f = get(0);
    f();
}

发出的主要功能:

define i32 @main() uwtable readnone {
  ret i32 0
}

因此,编译器能够了解选择了哪个函数(结合内联和常量传播),并进行内联调用。

不幸的是,我在我的电子邮件中演示了通过虚拟表这不起作用(优化器不知何故丢失了信息并且无法内联调用)。因此,虽然内联完全有可能通过std::function,但它很可能不仅取决于编译器,还取决于std::function您碰巧使用的特定实现。恐怕您需要对您的应用程序进行试验。

于 2012-09-29T17:57:52.687 回答