我正在研究本文中阐述的静态运算符()的动机
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1169r2.html
他们解释说,STL 算法中经常使用的函数对象会产生将其 this 指针存储在寄存器中的额外成本,即使operator() 不使用它。
为此他们给出了以下代码示例: https://godbolt.org/z/ajTZo2
运行算法以使用函数对象的静态函数而不是非静态运算符()确实会产生更短的汇编代码。 (他们使用 -DSTATIC 运行一次,不使用 -DSTATIC 运行一次)
struct X {
bool operator()(int) const;
static bool f(int);
};
inline constexpr X x;
int count_x(std::vector<int> const& xs) {
return std::count_if(xs.begin(), xs.end(),
#ifdef STATIC
X::f
#else
x
#endif
);
}
但是,当我更改函数以实际执行某些操作时,无论是仅返回 true,还是将参数与硬编码值进行比较,差异似乎消失了,并且生成的程序集似乎是相同的,让我仍在搜索为了利用静态运算符()的优势。
#include <vector>
#include <algorithm>
using namespace std;
struct X {
bool operator()(int data ) { return data > 5; } ;
static bool f(int data) { return data > 5; } ;
};
inline constexpr X x;
int count_x(std::vector<int> const& xs) {
return std::count_if(xs.begin(), xs.end(),
#ifdef STATIC
X::f
#else
x
#endif
);
}
谁能解释一下吗?
编辑: 顺便说一句,将代码更改为以下内容,返回汇编差异
struct X {
bool operator()(int data ) ;
static bool f(int data);
};
__attribute__ ((noinline)) bool X::operator() (int data) {
{ return data > 5; }
}
__attribute__ ((noinline)) bool X::f(int data )
{ return data > 5; }
inline constexpr X x;
int count_x(std::vector<int> const& xs) {
return std::count_if(xs.begin(), xs.end(),
#ifdef STATIC
X::f
#else
x
#endif
);
}
如果函数被内联,那么当然实际的调用约定是什么并不重要——它被内联了。但是该函数不会内联,那么您必须发出对该函数的调用 - 这最终会做不必要的工作。
这基本上就是能够将调用运算符注释为
static
的要点。如果不需要对象参数,只需从签名中明确表示不需要对象参数即可。您已经可以在命名函数上执行此操作,只是如果您的成员函数碰巧被命名为 ()
,则无法执行此操作。这是一种武断的限制,使您无法清楚地表达您的意图。
此外,它使编译器的工作变得更容易——如果一开始就没有对象参数,则不必优化对象参数。内联失败是一种致命的千刀万剐的考验,所以每一点都有帮助。
(来源:这是我的建议)