2012-12-02 2 views
7

In Bezug auf Function passed as template argument, die Community-Wiki-Antwort von Ben Supnik zur Verfügung gestellt diskutiert das Problem der inline-instanziierten Funktionsvorlagen.Warum ist es klar, dass die Instanziierung einer Template-Funktion nicht inline erfolgt?

In dieser Antwort ist der folgende Code:

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); 

Die Antwort geht auf das zu sagen (in Bezug auf die letzte Zeile, die die Funktion Vorlage do_op instanziiert): Diese

deutlich wird nicht inline.

Meine Frage ist: Warum ist klar, dass dies nicht inline wird?

Antwort

5

Was er sagt (ich denke) ist, dass die add Funktion nicht inline wird. Mit anderen Worten könnte der Compiler do_op wie folgt Inline:

int c = func_ptr(4, 5); 

aber es wird nicht auch add wie folgt Inline:

int c = 4 + 5; 

er jedoch in diesem einfachen Beispiel falsch sein könnte.

Im Allgemeinen, wenn Sie eine Funktion über einen Zeiger aufrufen, kann der Compiler (zur Kompilierzeit) nicht wissen, welche Funktion Sie aufrufen, so dass die Funktion nicht inline eingebunden werden kann. Beispiel:

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

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

Hier kann der Compiler nicht wissen, ob callThroughPointerf1 oder f2 nennen, so gibt es keine Möglichkeit für sie entweder f1 oder f2 in callThroughPointer Inline.

Wenn der Compiler jedoch zur Kompilierzeit beweisen kann, welche Funktion aufgerufen wird, darf die Funktion inline eingebunden werden. Beispiel:

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

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

Hier kann der Compiler beweisen, dass f immer f1 sein wird, so ist es erlaubt f1 in callThroughPointer2 Inline. (Das bedeutet nicht, es wird Inline f1 ...)

Auch im Beispiel Sie in Ihrem Beitrag zitiert, der Compiler kann beweisen, dass func_ptr immer add im Aufruf do_op, so ist es erlaubt Inline add . (Das bedeutet nicht, es wird Inline add ...)

0

Warum ist es klar, dass dies nicht inlined bekommen?

Es ist nicht. Es gibt keinen Grund, warum der Compiler den gesamten Code in diesem Code nicht inline einbinden könnte.

+1

Es gibt keinen Grund, warum es nicht könnte, aber es gibt viele Gründe, warum es nicht einmal versuchen würde, das zu tun. Wenn ich nicht falsch informiert bin, haben C (und C++) Compiler nicht einmal versucht, Funktionszeiger zum Zwecke des Inlinens bis vor kurzem zu verfolgen. –

+1

@KonradRudolph - sicher, aber die Behauptung ist, dass ** es ist klar, dass dies nicht inline wird **. Es ist überhaupt nicht klar. –

3

Beim Aufruf einer Funktion über einen Funktionszeiger ist es sehr unwahrscheinlich, dass der Compiler den Aufruf über den Funktionszeiger vermeidet.Nur wenn der Compiler nachweisen kann, dass er weiß, womit der Funktionszeiger initialisiert wird und dass er nicht verändert werden kann, könnte er möglicherweise den Funktionsaufruf durch den Funktionszeiger vermeiden und damit die Funktion inline machen. In dem zitierten Setup, das heißt

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

die Funktionszeiger func_ptr veränderbar sind und der Compiler ist also nicht garantiert, dass es nie ändern wird. Daher kann der Aufruf an add möglicherweise nicht inline eingebunden werden.

Wenn der Codeschnipsel in der Tat abgeschlossen ist, passieren Dinge während der Initialisierung und der Compiler könnte tatsächlich wissen, dass func_ptr initialisiert wird, um add zu enthalten.

+0

Sehr nützlich ... Ich wünschte, ich könnte mehrere Antworten als die akzeptierte Antwort markieren. –

Verwandte Themen