2016-06-20 10 views
6

Rozważmy następujący konstruktordlaczego domyślny argument nie może zależeć od innego niż domyślny argumentu?

class MyClass { 
    MyClass(unsigned int dimension, std::vector vector=unitaryVector(dimension)); 
}; 

gdzie unitaryVector(d) to funkcja zwraca losową std::vector w d wymiarach.

To daje następujący błąd kompilatora:

error: default argument references parameter 'dimension' 
    MyClass(unsigned int dimension, std::vector vector=unitaryVector(dimension)); 

Dlaczego nie jest to idiom ważne w C++ 11? Wydaje się to dość oczywiste: jeśli podano argument vector, init vector jako kopia argumentu, w przeciwnym razie wywołaj funkcję i zainicjuj ją jako kopię zwracanej wartości. Dlaczego kompilator nie może tego zrozumieć?

+0

Twoja prośba o funkcję wydaje się być bardzo rozsądną rzeczą, ale czy jest w standardzie? Jeśli nie, autorzy kompilacji nie są zobowiązani do jego implementacji. – pyon

+1

możliwy duplikat http://stackoverflow.com/questions/1880866/cc-default-argument-set-as-a-previous-argument –

+0

Możesz użyć std :: optional <> z domyślną wartością empty zamiast wyraźna wartość domyślna. Ma to tę zaletę, że wartość domyślna nie będzie częścią ABI i dlatego łatanie będzie łatwiejsze. – lorro

Odpowiedz

9

++ średnia C zabrania.

dcl.fct.default

9 default argument is evaluated each time the function is called with no argument for the corresponding parameter. A parameter shall not appear as a potentially-evaluated expression in a default argument. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names.

[ Example:

int a; 
int f(int a, int b = a);   // error: parameter a 
            // used as default argument 
typedef int I; 
int g(float I, int b = I(2));  // error: parameter I found 
int h(int a, int b = sizeof(a)); // OK, unevaluated operand 

— end example ]

Zauważ, że domyślne argumenty są zastąpiony w miejscu połączenia Jeśli nie podana

Intro.execution(Kopalnia nacisk)

11:[ Note: The evaluation of a full-expression can include the evaluation of subexpressions that are not lexically part of the full-expression. For example, subexpressions involved in evaluating default arguments ([dcl.fct.default]) are considered to be created in the expression that calls the function, not the expression that defines the default argument. — end note ]


można po prostu przeciążać konstruktora i przekazać go:

class MyClass { 
    explicit MyClass(unsigned int dimension) 
     : MyClass(dimension, unitaryVector(dimension)) //delegation 
    { } 
    MyClass(unsigned int dimension, std::vector vector); 
}; 

Przypis: Jest to dobra rzecz, aby pojedyncze konstruktorów argumentów explicit

1

Ponieważ domyślny argument musi być kompletny sam w sobie, aby kompilator mógł go po prostu zastąpić, jeśli nie został dostarczony przez wywołanie. Zmienna (lokalna) dimension nie została jeszcze utworzona i próbujesz jej użyć, a tym samym błąd. To będzie działać, jednakże:

int _def_dim=10; 
class MyClass { 
    MyClass(unsigned int dimension, std::vector vector=unitaryVector(_def_dim)); 
}; 

Nie jestem pewien, co standardowe mówi, ale dla realizacji kompilator byłoby trudne w obsłudze takich przypadków rożny.

EDIT (do uzupełnienia) pobrana z this answer:

Default arguments are evaluated each time the function is called. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in default argument expressions, even if they are not evaluated.

1

Alternatywą jest użycie

class MyClass { 
    MyClass(unsigned int dimension, std::vector const& vector) : 
      dimension(dimension), vector(vector) {} 

    MyClass(unsigned int dimension) : 
      MyClass(dimension, unitaryVector(dimension)) {} 
}; 

(to oczywiście, gdy chcesz zapisać dimension i vector w klasie).

Powiązane problemy