2012-12-02 8 views
7

Function passed as template argumentについては、Ben Supnikによって提供されたコミュニティWikiの回答が、インスタンス化された関数テンプレートのインライン化の問題について説明しています。その答えはテンプレート関数のインスタンス化がインライン化されないことが明らかなのはなぜですか?

次のコードです:

template<typename OP> 
int do_op(int a, int b, OP op) 
{ 
    return op(a,b,); 
} 

int add(int a, b) { return a + b; } 

int (* func_ptr)(int, int) = add; 

int c = do_op(4,5,func_ptr); 

答えは(関数テンプレートdo_opをインスタンス化し、最終的なライン、との点で)これを言うためにに行く:

明確にこのインラインになっていません。

私の質問は次のとおりです。なぜこれがインライン化されていないのは明らかですか?

答えて

5

彼が言っていることは、add関数がインライン化されていないということです。言い換えれば、コンパイラは、このようなdo_opをインライン化があります

int c = func_ptr(4, 5); 

それはまた、このようなaddをインライン化しません。

int c = 4 + 5; 

しかし、彼はその簡単な例では間違っている可能性があります。

一般に、ポインタを使用して関数を呼び出すと、コンパイラは呼び出す関数を(コンパイル時に)知ることができないため、関数をインライン化できません。例:

ここ
void f1() { ... } 
void f2() { ... } 

void callThroughPointer() { 
    int i = arc4random_uniform(2); 
    void (*f)() = i ? f2 : f1; 
    f(); 
} 

、コンパイラはcallThroughPointerf1またはf2を呼び出すかどうかを知ることができないので、それはcallThroughPointerf1またはf2のいずれかをインライン化するための方法はありません。

しかし、コンパイラがコンパイル時にどの関数が呼び出されるかを証明できれば、その関数をインライン化することができます。例:ここでは

void f1() { ... } 
void f2() { ... } 

void callThroughPointer2() { 
    int i = arc4random_uniform(2); 
    void (*f)() = i ? f2 : f1; 
    f = f1; 
    f(); 
} 

、コンパイラはfは常にf1になることを証明することができ、それはcallThroughPointer2f1をインライン化することができます。

同様に、あなたがあなたの記事で引用された例では、コンパイラは、addのインライン化を許可されていますのでfunc_ptrは、常にdo_opへの呼び出しでaddであることを証明することができます(これはますインラインf1 ...それを意味するものではありません) 。

0

なぜそれが、これはインライン化取得されていないことは明らかである(それは...それますインラインadd意味するものではありませんか)?

そうではありません。コンパイラがそのスニペットのすべてのコードをインライン化できない理由はありません。

+1

それはできないかもしれない理由はありませんが、それをしようとしない理由もたくさんあります。私が誤って知らされていないなら、C(およびC++)コンパイラはかなり最近までインライン化の目的で関数ポインタの追跡を試みていませんでした。 –

+1

@ KonradRudolph - 確かに、それは**インラインになっていないことは明らかです**。それはまったく明らかではありません。 –

3

関数ポインタを使用して関数を呼び出すと、コンパイラは関数ポインタによる呼び出しを避けることはほとんどありません。コンパイラが、関数ポインタが初期化されていることがわかっており、変更できないことを証明できる場合にのみ、関数ポインタを介して関数呼び出しを回避し、関数をインライン化する可能性があります。引用されたセットアップ、すなわち、

int (* func_ptr)(int, int) = add; 

で関数ポインタfunc_ptrは変更可能であると、コンパイラは、このように、それは決して変わらないことを保証するものではありません。その結果、addへの呼び出しをインライン化することはできません。

コードのスニペットが実際に完了していると、初期化中に何かが発生し、実際にはfunc_ptraddを含むように初期化されていることが実際に分かります。

+0

非常に便利です...私は受け入れられた答えとして複数の回答をマークできたらいいですね。 –

関連する問題