2015-08-16 3 views
7

Zum Beispiel, warum kann ich nicht schreiben:Warum kann ich vorherige Argumentwerte nicht verwenden, um Argumentstandardwerte zu definieren?

void f(double x, double y = x); 

eine Funktion f zu erklären, für die f(x) der Aufruf von f(x,x) entspricht?

Falls Ihnen das nicht nützlich erscheint, hier ein mögliches Anwendungsszenario. In diesem Beispiel erkläre ich f wie folgt:

void f(double x, double y = expensiveComputation(x)); 

wo expensiveComputation bedeutet, Sie ahnen es, eine Funktion, die eine sehr langsame Berechnung der Fall ist. Ich möchte dem Benutzer von f die Möglichkeit geben, den Wert von y zu übergeben, wenn er es zuvor berechnet hat, also muss ich es innerhalb f nicht erneut berechnen. Nun, natürlich kann ich dies auch durch das Schreiben zwei Überlastungen beheben:

void f(double x, double y); 
void f(double x) { f(x, expensiveComputation(x)); } 

aber Überlastungen Schreiben wird ermüdend wie die Anzahl der Argumente wächst. Versuchen Sie beispielsweise zu schreiben:

mit Überladungen. Es ist nur hässlicher. Standardargumente sind sexy. Gibt es einen tieferen syntaktischen Grund, warum vorherige Argumente nicht zum Definieren von Argument-Standardwerten verwendet werden können?

+3

Wenn Sie diese Syntax zulassen, würde die Implementierung Argumente von links nach rechts auswerten? – Brian

+0

@Brian Guter Punkt. Warum ist die Implementierung nicht gezwungen, Argumente von links nach rechts zu bewerten? Ich habe vergessen ... – becko

+0

Auf vielen Plattformen ist die Standardaufrufkonvention, Argumente von links nach rechts auf den Stapel zu schieben. (Der Aufgerufene erscheint dann von links nach rechts.) – Brian

Antwort

0

können Sie variadische Vorlagen für etwas ähnliches verwenden:

template<typename... Args> void f(double x, Args... args) 
{ 
    typedef typename common_type<double, Args...>::type common; 
    std::vector<common, sizeof...(args)> arguments = {{ args... }}; 

    if (arguments.size < 2) arguments.push_back(expensiveComputation(arguments[0])); 
    if (arguments.size < 3) arguments.push_back(expensiveComputation2(arguments[0], arguments[1])); 
    if (arguments.size < 4) arguments.push_back(expensiveComputation3(arguments[0], arguments[1], arguments[2])); 
    if (arguments.size < 5) arguments.push_back(expensiveComputation4(arguments[0], arguments[1], arguments[2], arguments[3])); 
} 
1

Ich weiß nicht, warum Standardargument nicht diesen Weg gehen können, aber vielleicht können Sie versuchen, all diese Argumente in einer Struktur zu umwickeln (Klasse)

struct ParamSet 
{ 
    double x; 
    double p; 
    double q; 

    ParamSet(double x) 
     : x(x) 
     , p(ExpensiveCompute1(x)) 
     , q(ExpensiveCompute2(x, p)) 
    { 
    } 
    ParamSet(double x, double p) 
     : x(x) 
     , p(p) 
     , q(ExpensiveCompute2(x, p)) 
    { 
    } 
    ParamSet(double x, double p, double q) 
     : x(x), p(p), q(q) 
    { 
    } 

private: 
    double ExpensiveCompute1(double x) {} 
    double ExpensiveCompute2(double x, double p) {} 
};  
void f(ParamSet ps); 

brauchen noch Ctor Überlastungen, aber nicht mehr Werke als das Schreiben die expensiveComputation() Serien wie Sie zur Verfügung gestellt, und zumindest alle Dinge in der Struktur gewickelten

Auch Unterschrift von f() behoben werden kann, und es ist nur 1 Version.

Verwandte Themen