メンバー関数ポインタがテンプレートパラメータとして使用されているときに何が起こっているのかを理解しようとしています。私はいつも関数ポインタ(またはメンバ関数ポインタ)は実行時のコンセプトだと考えていたので、テンプレートパラメータとして使用するとどうなるのだろうかと思っていました。 callF
は、比較のためにあるなぜgccとclangはメンバ関数のテンプレートパラメータに非常に異なるコードを生成するのですか?
struct Foo { void foo(int i){ } };
template <typename T,void (T::*F)(int)>
void callFunc(T& t){ (t.*F)(1); }
void callF(Foo& f){ f.foo(1);}
int main(){
Foo f;
callF(f);
callFunc<Foo,&Foo::foo>(f);
}
:このような理由から、私はこのコードによって生成された出力を見ていました。
callF(Foo&): # @callF(Foo&)
push rbp
mov rbp, rsp
sub rsp, 16
mov esi, 1
mov qword ptr [rbp - 8], rdi
mov rdi, qword ptr [rbp - 8]
call Foo::foo(int)
add rsp, 16
pop rbp
ret
が、テンプレートのインスタンス化のために非常に異なる出力:clang 3.9
はcallF()
でほぼ同じ出力を生成しながら
callF(Foo&): // void callFunc<Foo, &Foo::foo>(Foo&):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, 1
mov rdi, rax
call Foo::foo(int)
nop
leave
ret
:
void callFunc<Foo, &Foo::foo>(Foo&): # @void callFunc<Foo, &Foo::foo>(Foo&)
push rbp
mov rbp, rsp
sub rsp, 32
xor eax, eax
mov cl, al
mov qword ptr [rbp - 8], rdi
mov rdi, qword ptr [rbp - 8]
test cl, 1
mov qword ptr [rbp - 16], rdi # 8-byte Spill
jne .LBB3_1
jmp .LBB3_2
.LBB3_1:
movabs rax, Foo::foo(int)
sub rax, 1
mov rcx, qword ptr [rbp - 16] # 8-byte Reload
mov rdx, qword ptr [rcx]
mov rax, qword ptr [rdx + rax]
mov qword ptr [rbp - 24], rax # 8-byte Spill
jmp .LBB3_3
.LBB3_2:
movabs rax, Foo::foo(int)
mov qword ptr [rbp - 24], rax # 8-byte Spill
jmp .LBB3_3
.LBB3_3:
mov rax, qword ptr [rbp - 24] # 8-byte Reload
mov esi, 1
mov rdi, qword ptr [rbp - 16] # 8-byte Reload
call rax
add rsp, 32
pop rbp
ret
gcc 6.2
は、両方の機能のために正確に同じ出力を生成します何故ですか? gcc
は(おそらく非標準の)ショートカットをとっていますか?
「-O3」?どのようなコンパイラ設定、まさに? – Yakk
@ Yakkよく、私はそれが最適化なしであることを認めなければなりません。私は観察可能な結果を生成する例を出す努力をしませんでした。 – user463035818