Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple declarations of C++ functions with default parameters

Tags:

c++

c++11

I use typedefs for almost everything, including functions. Over the past few weeks, I have been tarting up our C++ code to conform as exactly as possible to the ISO C++11 standard, using the final draft document (N3242) as a guide.

As we know, there are occasional multiple declarations that creep into our code through externs appearing in more than one file, or typedefs that are repeated. According to this excerpt from section 7.1.3, page 145 of the above doco, this should be harmless:

3. In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.

[ Example:

   typedef struct s { /* ... */ } s; 
   typedef int I; 
   typedef int I; 
   typedef I I;

— end example ]

So, I wrote a program to test this. In its simplest form:

typedef int (fcntype)(int, int);
extern fcntype fcn1;

int fcn1(int x, int y) { return x + y; }

int main(int argc, char ** argv) { return fcn1(2, 3); }

Compiling using gcc with

 -Wfatal-errors -Wswitch-default -Wswitch-enum -Wunused-parameter -Wfloat-equal -Wundef -c -Wstrict-null-sentinel -std=c++0x -pedantic -Wall -Wextra

there are, of course, no problems. Let's dup the function decl:

typedef int (fcntype)(int, int);
extern fcntype fcn1;
extern fcntype fcn1; // woops. probably from an #include ...

int fcn1(int x, int y) { return x + y; }

int main(int argc, char ** argv) { return fcn1(2, 3); }

As the standard predicts, no problems. Let's make a different change to the original:

typedef int (fcntype)(int, int=0); // default param.
extern fcntype fcn1;

int fcn1(int x, int y) { return x + y; }

int main(int argc, char ** argv) { return fcn1(2); } // use the default param

Again, no problems. The problem comes about when we have both the duplicate decl and the defaulted parameter like this:

typedef int (fcntype)(int, int=0); // default param.
extern fcntype fcn1;
extern fcntype fcn1; // FYI this is line 3 in the error message below.

int fcn1(int x, int y) { return x + y; }

int main(int argc, char ** argv) { return fcn1(2); } // use the default param

And gcc complains with

decltest.cpp:3: error: default argument given for parameter 2 of ‘int fcn1(int, int)’

Of course, I am cleaning up the code the way it should be cleaned up, which is to say I am corralling the decls into one, better organized file. But is this a bug in the compiler or a misunderstanding of mine about what a default parameter "is"?

like image 636
George Flanagin Avatar asked Jul 15 '11 14:07

George Flanagin


2 Answers

Firstly, for the same function declaration with same types, there should only be at most one declaration which define the default arguments. This is due to §8.3.6 [dcl.fct.default]/4:

... A default argument shall not be redefined by a later declaration (not even to the same value). [ Example:

...
void m() {
    void f(int, int);     // has no defaults
    f(4);                 // error: wrong number of arguments
    void f(int, int = 5); // OK
    f(4);                 // OK, calls f(4, 5);
    void f(int, int = 5); // error: cannot redefine, even to same value
}
...

end example ] ...

Also, as @Sven noticed, a default argument shall not appear in a typedef, although g++ cannot catch it even with -pedantic. I think clang and Visual C++ reject this but I haven't tried.

like image 88
kennytm Avatar answered Oct 22 '22 08:10

kennytm


Your standard quote doesn't apply here, since you're not declaring the typedef multiple times, but using it multiple times.

Default arguments are indeed a tricky case, they can only appear in one declaration (and remember, the definition itself counts as a declaration, even putting the default argument in both a forward declaration and a definition is an error).

like image 39
Ben Voigt Avatar answered Oct 22 '22 08:10

Ben Voigt