我使用GCC4.9.2和clang3.6.0编译了以下c 14代码.
我用-O3标志.
#include <utility>
struct S
{
int a;
int A () const { return a; }
};
template <class F, class ... Args>
int Func (F && f, Args && ... args)
{
return f(std::forward<Args>(args) ...);
}
using PtrA = int (S::*)() const;
int F (S const & s, PtrA ptr) { return (s.*ptr)() * 5; }
int p (S const & s) { return s.A() * 5; }
int P1 (S const & s) { return Func(&F, s , &S::A); }
int P2 (S const & s) { return Func([](S const & s, auto f) { return (s.*f)() * 5; }, s, &S::A); }
int P3 (S const & s) { return ([](S const & s, auto f) { return (s.*f)() * 5; })(s, &S::A); }
int P4 (S const & s) { return Func([](S const & s) { return s.A() * 5; }, s); }
Func通过向函数对象传递参数来调用委托的函数对象.
P1,P2,P3和P4与p的工作方式不同.
P1委托F,它是涉及成员函数指针(PtrA)的函数.
P2委托lambda函数,它的作用与F相同.
P3直接调用lambda函数.
P4在不使用成员函数指针的情况下调用另一个lambda函数.
与GCC对此代码的objdump是
// p, P1, P3, P4
mov (%rdi),%eax
lea (%rax,%rax,4),%eax
retq
// P2
sub $0x8,%rsp
callq 49 <_Z2P2RK1S+0x9> // this address points to "add" in the next line.
add $0x8,%rsp
lea (%rax,%rax,4),%eax
retq
对于p,P1,P3,P4,GCC输出良好的代码.
奇怪的是,对于P2,GCC显然输出了错误的代码.
另一方面,clang输出
// p, P1, P2, P3, P4
imul $0x5,(%rdi),%eax
retq
虽然这不是很好,但至少所有功能的输出都是相同的.
我的问题是,是否有正确的理由,GCC无法优化这一点,即p和P1-P4之间存在C程序的差异.
如果第一个问题的答案为否,那么这是GCC优化器中的已知错误吗?
这个问题的动机是a Japanese article
最佳答案 似乎GCC 5及其后续实际上能够进行优化,参见
gcc.godbolt.org:
P2(S const&):
mov eax, DWORD PTR [rdi]
lea eax, [rax+rax*4]
ret