TITLE: default values and overloading (Newsgroups: comp.std.c++, 10 Feb 99) ALEXANDRESCU: "Andrei Alexandrescu" >>void foo(int =1 ,int =2 ,int=3); >>void foo(double=1.0,double=2.0,int=3); >> >>>| foo(default, default, 4); NARAN: Siemel Naran >>Which foo(...) called? GLASSBOROW: Francis Glassborow >but the same question can be asked of: > >foo(); > >You cannot default all the parameters (or even all the trailing >parameters if the leading ones have a common sequence of types. CLAMAGE: Steve Clamage Here's a hypothetical example without those faults: void foo(int = 1, double = 2.0, int); void foo(double = 3.0, int = 4 , int); foo(default, default, 5); // which foo? It's easy to say, "OK, that case is ambiguous, but we'll keep the feature." The real problem is that default parameters interact badly with overloading, and proposals such as this one just make it worse. IMHO, we don't really need more opportunities for ambiguous function calls. In addition, default arguments have their own sets of problems. For one thing, the binding of default arguments sometimes surprises programmers. extern int i; ... int foo(int = i); // default is the global i ... int bar() { int i = 3; foo(); // incorrectly thinks 3 is the default value ... } For another, you can accidently have different defaults for the same function in different files and get an unexpected result. (To be fair, having different sets of overloaded function declarations in different translation units can also cause surprises.) It's worth noting that default parameters appeared originally in C++ because function overloading at the time was difficult to use and error-prone. You had to ensure that all declarations for all overloads of a function appeared in the same sequence in every translation unit. The invention of type-safe linkage in 1989 ("name mangling") removed that difficulty. You can usually get the same effect with function overloading that you would otherwise get with default parameter values. Simple example with "forwarding functions": Instead of int foo(int=1, double=2.0); you can write int foo(int, double); // the "real" function inline int foo(int j) { return foo(j, 2.0); } inline int foo(double d) { return foo(1, d); } inline int foo() { return foo(1, 2.0); } This forwarding-function technique doesn't have the inline advantage for virtual functions, and can't be used at all for constructors. In those cases you have to repeat code or call a common subroutine. Lawrence Crowl has suggested the language be extended to allow "forwarding constructors". Example: class T { T(int); // the "real" constructor T() : T(3) { } // forwarding constructor This pair of constructors would have the effect of T(int=3) I don't see any problems with this extension, although one compiler writer said he didn't see how to implement it. (When this particular person can't see a way to implement it, I assume I have missed something.) If feasible, it would go a long way to elmininating the need for default arguments.