コンパイラがあらゆる機会に行うインライン化では問題はありません。問題は、Visual C++ではポインタ変数が実際にコンパイル時定数であることを認識していないように見えることです。
テストケース:
// function_pointer_resolution.cpp : Defines the entry point for the console application.
//
extern void show_int(int);
extern "C" typedef int binary_int_func(int, int);
extern "C" binary_int_func sum;
extern "C" binary_int_func* const sum_ptr = sum;
inline int call(binary_int_func* binary, int a, int b) { return (*binary)(a, b); }
template< binary_int_func* binary >
inline int callt(int a, int b) { return (*binary)(a, b); }
int main(void)
{
show_int(sum(1, 2));
show_int(call(&sum, 3, 4));
show_int(callt<&sum>(5, 6));
show_int((*sum_ptr)(1, 7));
show_int(call(sum_ptr, 3, 8));
// show_int(callt<sum_ptr>(5, 9));
return 0;
}
// sum.cpp
extern "C" int sum(int x, int y)
{
return x + y;
}
// show_int.cpp
#include <iostream>
void show_int(int n)
{
std::cout << n << std::endl;
}
機能がインラインより良好な制御を与えるために複数のコンパイル単位に分離されます。具体的には、show_int
をインライン化したくないのは、アセンブリコードが乱雑になるからです。
問題の最初の悩みは、有効なコード(コメント行)がVisual C++によって拒否されることです。 G++ has no problem with itですが、Visual C++では「期待されるコンパイル時定数式」が返されます。これは、実際にはすべての将来の行動の良い予測子です。最適化が有効と通常のコンパイルセマンティクス(ノークロスモジュールのインライン化)で
、コンパイラが生成します。
_main PROC ; COMDAT
; 18 : show_int(sum(1, 2));
push 2
push 1
call _sum
push eax
call [email protected]@[email protected] ; show_int
; 19 : show_int(call(&sum, 3, 4));
push 4
push 3
call _sum
push eax
call [email protected]@[email protected] ; show_int
; 20 : show_int(callt<&sum>(5, 6));
push 6
push 5
call _sum
push eax
call [email protected]@[email protected] ; show_int
; 21 : show_int((*sum_ptr)(1, 7));
push 7
push 1
call DWORD PTR _sum_ptr
push eax
call [email protected]@[email protected] ; show_int
; 22 : show_int(call(sum_ptr, 3, 8));
push 8
push 3
call DWORD PTR _sum_ptr
push eax
call [email protected]@[email protected] ; show_int
add esp, 60 ; 0000003cH
; 23 : //show_int(callt<sum_ptr>(5, 9));
; 24 : return 0;
xor eax, eax
; 25 : }
ret 0
_main ENDP
sum_ptr
を使用してsum_ptr
していないを使用しての間には大きな違いがすでにあります。 sum_ptr
を使用しているステートメントは、間接的な関数呼び出しcall DWORD PTR _sum_ptr
を生成しますが、他のすべてのステートメントは、ソースコードが関数ポインタを使用している場合でも、直接関数呼び出しcall _sum
を生成します。
function_pointer_resolution.cppとsum.cppを/GL
でコンパイルし、/LTCG
でリンクしてインライン化を有効にすると、コンパイラはすべての直接呼び出しをインライン化することがわかります。間接通話は現状のままです。
_main PROC ; COMDAT
; 18 : show_int(sum(1, 2));
push 3
call [email protected]@[email protected] ; show_int
; 19 : show_int(call(&sum, 3, 4));
push 7
call [email protected]@[email protected] ; show_int
; 20 : show_int(callt<&sum>(5, 6));
push 11 ; 0000000bH
call [email protected]@[email protected] ; show_int
; 21 : show_int((*sum_ptr)(1, 7));
push 7
push 1
call DWORD PTR _sum_ptr
push eax
call [email protected]@[email protected] ; show_int
; 22 : show_int(call(sum_ptr, 3, 8));
push 8
push 3
call DWORD PTR _sum_ptr
push eax
call [email protected]@[email protected] ; show_int
add esp, 36 ; 00000024H
; 23 : //show_int(callt<sum_ptr>(5, 9));
; 24 : return 0;
xor eax, eax
; 25 : }
ret 0
_main ENDP
ボトムライン:はい、コンパイラは限りその関数ポインタを変数から読まれていないとして、コンパイル時定数関数ポインタを介して行わインライン呼び出しを行います。
call(&sum, 3, 4);
が、これはしなかった:関数ポインタのこの使用が最適化されてしまった
(*sum_ptr)(1, 7);
すべてのテストは、x64上でホストされているx86の、用にコンパイルは、Visual C++ 2010のService Pack 1で実行されます。
のMicrosoft(R)32ビットのC/C++最適化コンパイラバージョン16.00.40219.01 80×86
何だろうgccはどうですか? –
@OtávioDécio私はGCCコンパイラを持っていないので、わかりません。 –
あなたは独自のコンパイラを使用しているので、答えを知っている人なら誰でも致命的な法的結果なしにあなたに伝えることはできません。 –