c++preprocessordefault-parameters

C2572 - When trying to include a function with a default parameter in another file, and then include this file in main


I am trying to build a small program in C++, to learn the preprocessor directives and how they actually work.

The program is made up of 5 files: main.cpp, file1.h, file1.cpp, file2.h and file2.cpp

In file1.h, I declared 1 function that has the default parameter, and a new type byte:

typedef unsigned char byte;

byte f1(byte a, byte b = 5);

In file1.cpp, I defined it:

#include "file1.h"

byte f1(byte a, byte b) {

    return a + b;
}

In file2.h, I declared a second function that uses f1(), and always passes 10 to it as a second argument:

#include "file1.h"

byte f2(byte a);

And the same, in file2.cpp, I defined it:

#include "file2.h"

byte f2(byte a) {

    return f1(a, 10);
}

And finally, here is the main file:

#include <iostream>
using namespace std;

#include "file1.h"

int main() {

    cout << f1(3) << endl;

    return 0;
}

For now, all is Ok, and the output is simply 8.

But suppose I need to use the f2() function in my main file, and for that I included the file2.h, so the main file is now:

#include <iostream>
using namespace std;

#include "file1.h"
#include "file2.h"

int main() {

    cout << (int) f1(3) << endl;

    cout << (int) f2(2) << endl;

    return 0;
}

The compiler is giving this error: Error C2572 'f1': redefinition of default argument: parameter 1

Since file1.h is included in file2.h, now f1() is redeclared in file2.h with the b paramter also set to 5.

What can I do to prevent the redefinition, if we assume that I can not move the f2() declaration and definition to file1.h and file1.cpp respectively?

Note: I know that I could use #pragma once directive, but I am trying to solve this problem without it, since I am trying to learn the C++ directives professionally.


Solution

  • In the code shown, byte and f1() are being declared multiple times in main.cpp when file1.h and file2.h are both #include'd.

    Per the C++ standard, §8.3.6 [dcl.fct.default]/4:

    [Note 2: A default argument cannot be redefined by a later declaration (not even to the same value) ([basic.def.odr]). — end note]

    Which is exactly what is happening here.

    Note: I know that I could use #pragma once directive, but I am trying to solve this problem without it, since I am trying to learn the C++ directives professionally.

    Making your .h files have proper header guards (see #pragma once vs include guards?) is the correct and professional way to avoid redeclarations, eg:

    file1.h:

    #ifndef File1H
    #define File1H
    
    typedef unsigned char byte;
    
    byte f1(byte a, byte b = 5);
    
    #endif
    

    file2.h:

    #ifndef File2H
    #define File2H
    
    #include "file1.h"
    
    byte f2(byte a);
    
    #endif
    

    Online Demo