2010-08-08 20 views
11

Betrachten Sie das folgende Snippet:Aus einer Void-Funktion in C Rückkehr ++

void Foo() 
{ 
    // ... 
} 

void Bar() 
{ 
    return Foo(); 
} 

Was einen legitimen Grund ist die oben in C++ zu verwenden, wie zu dem häufigeren Ansatz gegen:

void Foo() 
{ 
    // ... 
} 

void Bar() 
{ 
    Foo(); 

    // no more expressions -- i.e., implicit return here 
} 

Antwort

16

Wahrscheinlich keine Verwendung in Ihrem Beispiel, aber es gibt einige Situationen, in denen es schwierig ist, mit void im Vorlagencode umzugehen, und ich erwarte, dass diese Regel manchmal dabei hilft. Sehr konstruiertes Beispiel:

#include <iostream> 

template <typename T> 
T retval() { 
    return T(); 
} 

template <> 
void retval() { 
    return; 
} 

template <> 
int retval() { 
    return 23; 
} 

template <typename T> 
T do_something() { 
    std::cout << "doing something\n"; 
} 

template <typename T> 
T do_something_and_return() { 
    do_something<T>(); 
    return retval<T>(); 
} 

int main() { 
    std::cout << do_something_and_return<int>() << "\n"; 
    std::cout << do_something_and_return<void*>() << "\n"; 
    do_something_and_return<void>(); 
} 

Beachten Sie, dass nur main mit der Tatsache fertig werden muss, dass im void Fall gibt es nichts von retval zurückzukehren. Die Zwischenfunktion do_something_and_return ist generisch.

Natürlich ist dies nur so weit kommt - wenn do_something_and_return wollte, im Normalfall, retval in einer Variablen zu speichern und mit ihm etwas tun vor der Rückkehr, dann würden Sie noch in Schwierigkeiten - du müss spezialisieren (oder überladen) do_something_and_return für void.

+0

Danke. Alle Antworten waren gut, aber dieser hat den Punkt schön illustriert. – kirk0

0

Die einzigen Grund, an den ich denken kann, ist, wenn Sie eine lange Liste von return Foo(); Anweisungen in einem Schalter hatten und es kompakter machen wollten.

9

Dies ist eine ziemlich nutzlose Konstruktion, die keinen Zweck erfüllt, es sei denn, sie wird mit Vorlagen verwendet. Das heißt, wenn Sie Vorlagenfunktionen definiert haben, die einen Wert zurückgeben, der 'ungültig' sein kann.

+4

dann ist es kaum "nutzlos", oder? ;) – jalf

+0

@jalf: Nun, in der Form ist es in der Frage gezeigt, es ist ziemlich nutzlos, oder? ;-) –

+0

wahr genug. Ich habe den Code in der Frage als Beispiel für das Sprachfeature interpretiert und gefragt, wann das Sprachfeature * im Allgemeinen * nützlich ist. Aber ein guter Punkt. ;) – jalf

7

Sie würden es in generischem Code verwenden, wo der Rückgabewert von Foo() unbekannt ist oder sich ändern kann. Erwägen:

In diesem Fall gilt Bar für ungültig, ist aber auch gültig, sollte sich der Rückgabetyp ändern. Wenn jedoch nur f aufgerufen wird, würde dieser Code brechen, wenn T nicht void wäre. Verwenden der Rückgabe f(); Die Syntax garantiert die Erhaltung des Rückgabewerts von Foo(), falls einer existiert, und ermöglicht void().

Darüber hinaus ist eine explizite Rückkehr eine gute Angewohnheit.

4

Vorlagen:

template <typename T, typename R> 
R some_kind_of_wrapper(R (*func)(T), T t) 
{ 
    /* Do something interesting to t */ 
    return func(t); 
} 

int func1(int i) { /* ... */ return i; } 

void func2(const std::string& str) { /* ... */ } 

int main() 
{ 
    int i = some_kind_of_wrapper(&func1, 42); 

    some_kind_of_wrapper(&func2, "Hello, World!"); 

    return 0; 
} 

Ohne Leere zurückkehren zu können, würden die return func(t) in der Vorlage nicht, wenn es zu wickeln func2 gefragt wurde.

0

Der Grund ist die Rückgabe von Speicher wie Math.h immer zurückkehrt. math.h hat keine Leere und keine leeren Argumente. Es gibt viele praktische Situationen, in denen Sie Speicher benötigen.

+0

Was?Die mathematischen Funktionen nehmen Argumente und Rückgabewerte, weil das ist, was sie mathematische Funktionen tun müssen, ... – GManNickG

0

Konnte ein Fall sein, in dem Foo() ursprünglich einen Wert zurückgab, aber später zu void geändert wurde, und die Person, die es gerade aktualisierte, dachte nicht sehr klar.

Verwandte Themen