   default arguments in functions
  I was just looking up how to provide default argument values in functions.  As it turns out, this is done in the prototype.  This is all good and well, except for the fact that I was always told to not include variable names in the prototype, only types.Why is this rule broken when we use default arguments?Wouldn't it just be easier on all of us if we always wrote the variable names in the prototypes?  Why would I have been taught not to?   
  What variable names is it you think you have to include?void foo(int = 42);;Quote:Original post by zoner7I was just looking up how to provide default argument values in functions.  As it turns out, this is done in the prototype.  Actually you have to have defined the default arguments at the point where you make use of underlying function. The following works fine:int foo (int a, int b, int c, int d) {   return a+b+c+d;}int foo (int a, int b, int c, int d = 0) ;int foo (int a, int b, int c=1, int d) ;int foo (int a, int b=0, int c, int d) ;int foo (int a=1, int b, int c, int d) ;int main () {   foo(0,0);}As you can see, it is even possible to provide multiple prototypes, but you may not override an existing default value, except the other prototype is not visible at that point. Note that if you have a function f(x_0, x_1, ..., x_n), and define a default value for some x_m, default values must also be visible for all x after x_m. Thus the following program is invalid:int foo (int a=1, int b, int c, int d) { return a+b+c+d; }int main () {}The same rule holds true for template parameters.   ;  Did they give any reason why you shouldn't use variable names in prototypes?If you do have variable names in prototypes, then looking at the prototype (perhaps your IDE shows it to you) you can pretty much tell how the function is to be used. Without the variable names, the prototype is much less useful for the developer (only something the compiler requires).;  wouldn't these be invalid because there are arguments without default values after those that are given default values.[source lang = cpp]int foo (int a, int b, int c=1, int d) ;int foo (int a, int b=0, int c, int d) ;int foo (int a=1, int b, int c, int d) ;the first one, however, would work because the only default value is the last argument and no other arguments without default values follow it.[source lang = cpp]int foo (int a, int b, int c, int d = 0) ;but anyhow.  Back to my original question.  So it is okay to define default values in either the prototype or the actual definition of the function?;Quote:Original post by zoner7wouldn't these be invalid because there are arguments without default values after those that are given default values.No, because you have already provided default arguments in another prototype for the same function.Imagine it like the compiler has a table of function prototypes in each translation unit (i.e. cpp-file), for each function. It could look likeNAME | RET  | ARG0-TYPE | ARG0-DEFAULT | ARG1-TYPE | ARG1-DEFAULT | ...foo  | int  | int  | -  | int  | -  | ...Now when the compiler see another prototype for a function that fits to the signature NAME+RET+ARG[0..x]-TYPE, he checks for the default arguments given in the new prototype:int foo (int, int = 42) ;He finds that for the second paramter a default argument is provided. Then he looks up the proper dataset in above table, and finds that no ARG1-DEFAULT is given yet. So he updates the table:NAME | RET  | ARG0-TYPE | ARG0-DEFAULT | ARG1-TYPE | ARG1-DEFAULT | ...foo  | int  | int  | -  | int  | 42 | ...Then he finds another prototype:int foo (int=0xDEADBEEF, int) ;and updates the table:NAME | RET  | ARG0-TYPE | ARG0-DEFAULT | ARG1-TYPE | ARG1-DEFAULT | ...foo  | int  | int  | 0xDEADBEEF   | int  | 42 | ...Now assume he finds yet another prototype:int foo (int, int=0) ;He again looks up the table, and finds that there is already a ARG1-DEFAULT, and gives a diagnostic.Another example.  Assume this time the following function:void bar (int, int) ;As usual, here's the lookup-table:NAME | RET  | ARG0-TYPE | ARG0-DEFAULT | ARG1-TYPE | ARG1-DEFAULT | ...bar  | void | int  | -  | int  | -  | ...Now he finds the following prototypevoid bar (int=42, int) ;This wouldn't make sense in C++, because you can't call a function in a way like "bar (, 50)". So upon lookup, the compiler always tests that for a new ARGn-DEFAULT, there is already a valid ARG(n+1)-DEFAULT. If not --> Diagnostic.   ;Quote:Original post by zoner7Why would I have been taught not to?Without variable names in the prototype's, functions are going to be FAR more obscure and harder to understand.  This reek's of a crazy lecturer's personal pet whim.  I can't even think of a time I've seen this done - never at work, never in any SDK's we use, and I've certainly never done it.  The ONLY reason I can see for this is to force you to write large comments blocks explaining things in your headers ... wich is why I think lecturer.  Comments are great, but making natural code harder to read to enforce them creates a far bigger problem IMHO!On a side note it'd be funny to see someone who hates variable names in prototypes code in java :P   ;  Using argument names in a prototype can also be useful when you're documenting the function (e.g. doxygen, javadoc).   ;Quote:Original post by phresnelQuote:Original post by zoner7wouldn't these be invalid because there are arguments without default values after those that are given default values.No, because you have already provided default arguments in another prototype for the same function.And I would personally shoot anyone who wrote production code that actually did that.  I generally frown upon using default arguments.  There's usually a better way, although I can't say I've never used them.  Just because C++ lets you do it, doesn't mean you should.I too agree that the idea of not naming the arguments in your prototypes is a Bad Idea.  Why purposefully make your code harder to understand?  Arguments have names for a reason.   ;Quote:Original post by MantearQuote:Original post by phresnelQuote:Original post by zoner7wouldn't these be invalid because there are arguments without default values after those that are given default values.No, because you have already provided default arguments in another prototype for the same function.And I would personally shoot anyone who wrote production code that actually did that.You wouldn't hit me, because I shoot first, as I write code faster and safer than you. Rule of thumb: The least error prone code is the one you don't write.Quote:I generally frown upon using default arguments.  There's usually a better way, although I can't say I've never used them.What is the usually better way? Overloading the function and introducing more space for programming failure?I give you an example of where default-arguments are a good thing to avoid code-duplication:enum MessageType {    error_message,    warning_message,    standard_message};void printMessage (std::string const &message, MessageType type=standard_message) {    const ConsoleColor prevCol = getForegroundColor();    switch (type) {    case error_message:   setForegroundColor (red);   break;    case warning_message:   setForegroundColor (yellow);   break;    case standard_message:   setForegroundColor (gray);   break;    };    print (message);    setForegroundColor (prevCol);}Now you can replace int main () {    printMessage ("hello", standard_message);    printMessage ("world", standard_message);    printMessage ("how", standard_message);    printMessage ("you", standard_message);    printMessage ("feel", standard_message);    printMessage ("today?", standard_message);}withint main () {    printMessage ("hello");    printMessage ("world");    printMessage ("how");    printMessage ("you");    printMessage ("feel");    printMessage ("today?");}And even the exotic "out-of-core-default-argument-addition" can be useful in some exotic cases, avoid code-duplication at very local places:void foo(char*, int) {}void bar () {   void foo (char* s, int=0xBEEF);   foo ("alpha");   foo ("bravo");   foo ("charlie");   foo ("delta");}int main () {   void foo (char* s, int=42);   foo ("alpha");   foo ("bravo");   foo ("charlie");   foo ("delta");}Never used the latter technique and surely it has limits, plus you shouldn't use it when it makes code non-intuitive (e.g. you shouldn't write code like "const float x = powf();", in that case it is indeed better to write a thin wrapper and give it a meaningful name).   