【发布时间】:2020-12-25 02:17:23
【问题描述】:
我正在编写一个涉及f = std::bind(std::bind(std::bind(...))) 使用的模板函数。
但我不确定 c++ 编译器是否足够聪明,可以展开调用链。
我的意思是:
- 创建仿函数
f时,是否有多个std::bind()在运行时调用? - 调用
f()时,是否涉及调用 多个operator()在bind_functor对象的不同层。
举个简单的例子:f2() 的运行速度是否比f1() 稍快一些?
#include <functional>
int add(int a, int b) {
return a + b;
}
int main() {
using namespace std::placeholders;
auto f1 = std::bind(std::bind(&add, 1, _1), 2);
auto f2 = std::bind(&add, 1, 2);
return 0;
}
更新:
我做了一些实验。看来f2() 确实比f1() 运行得快。如果你使用std::function,它会更慢。这是实验代码(ubuntu/gcc 7.5.0,启用优化。没有优化,f2 是最慢的。)。在我的电脑上,输出是:
f1: 16851813
f2: 17567904
f3: 30655284
代码如下(根据Nate的评论更新):
#include <chrono>
#include <iostream>
#include <functional>
int add(int a, int b, int c) {
return a + b + c;
}
int main() {
using namespace std::placeholders;
auto f1 = std::bind(std::bind(&add, 1, _1, _2), 2, _1);
auto f2 = std::bind(&add, 1, 2, _1);
std::function<int(int)> f3 = std::bind(&add, 1, 2, _1);
const int N = 10000000;
volatile int x = 0;
{
auto begin = std::chrono::system_clock::now();
for (int n = 0; n < N; n++) {
x = f1(x);
}
auto end = std::chrono::system_clock::now();
auto d = end - begin;
std::cout << "f1: " << d.count() << std::endl;
}
x = 0;
{
auto begin = std::chrono::system_clock::now();
for (int n = 0; n < N; n++) {
x = f2(x);
}
auto end = std::chrono::system_clock::now();
auto d = end - begin;
std::cout << "f2: " << d.count() << std::endl;
}
x = 0;
{
auto begin = std::chrono::system_clock::now();
for (int n = 0; n < N; n++) {
x = f3(x);
}
auto end = std::chrono::system_clock::now();
auto d = end - begin;
std::cout << "f3: " << d.count() << std::endl;
}
return 0;
}
【问题讨论】:
-
对于 g++ 10.2,您的测试结果可以通过以下事实来解释:gcc 注意到
f1()和f2()没有副作用并且它们的返回值未使用,因此可以优化它们。因此,您的测试正在测量根本不执行任何操作所花费的时间。 godbolt.org/z/TM61b7,请注意,前两个测试中的每一个都只是编译成对now()的背靠背调用,中间没有循环或其他任何东西。我认为这不是您想要衡量的。 -
感谢您的评论,内特。我已经更改了代码,以便 f1() f2() 和 f3() 的返回值都将被使用。但我仍然得到了类似的结果,即:就使用的循环时间而言,f2
-
我尝试使用 godbolt.org。这是一个非常好的工具。我需要更好地了解汇编才能理解编译后的代码。
-
在使用 -O2 为 x64 编译的 Visual C++ 2019 中,我观察到
f1和f2都内联到一个简单的添加中,而f3是对函子实现的调用。差异可以通过编译器中的内联启发式来解释。
标签: c++ functor std-function stdbind