Search code examples
c++forward-declarationdefault-arguments

Default parameters and forward declaration


I have a class Property with a constructor in which I want default parameters, in a file property.h:

class Property {
  Property(OtherClass* value = myApp->someValue) {...};
};

where myApp, of another type Application, is defined in another file that makes extensive use of this Property class. Since this other file #includes property.h, of course, I cannot #include this file in property.h

property.h does not know about myApp nor Application (though property.cpp does, and OtherClass is known in property.h). I could forward declare OtherClass and declare myApp as extern, but this results in an error C2027 "use of undefined type Application", as expected :

class Application;
extern Application* myApp;
class Property {
  Property(OtherClass* value = myApp->someValue) {...};
};

A solution could be to have the default parameter in the .cpp file, but this is not advisable (here).

How can I get this default parameter working ? (i.e., not another solution that would involve not having default parameters telling me default parameters are evil, or that my design is poor to start with etc. ;) ). Thanks!


Solution

  • The remarkable point is that the default argument of function parameters is resolved where the function is called (in opposition to where the function is defined). That gives the necessary space to solve OPs problem by yet another level of indirection:

    Instead of accessing myApp->someValue, a helper function is introduced, which can be declared before the definition of Property but implemented after Application is fully defined. (This could be a static member function of Property as well.)

    An example to demonstrate:

    #include <iostream>
    
    int getAppDefault();
    
    struct Application;
    extern Application *pApp;
    
    struct Property {
      int value;
      Property(int value = getAppDefault()): value(value) { }
    };
    
    struct Application {
      int valueDefault = 123;
    };
    
    Application app;
    Application *pApp = &app;
    
    int getAppDefault() { return pApp->valueDefault; }
    
    int main()
    {
      Property prop1;
      std::cout << "prop1: " << prop1.value << '\n';
      app.valueDefault = 234;
      Property prop2;
      std::cout << "prop2: " << prop2.value << '\n';
    }
    

    Output:

    prop1: 123
    prop2: 234
    

    Demo on coliru

    To emphasize that value = getAppDefault() is in fact resolved when the constructor Property::Property() is called, I modified the Application::valueDefault before default-constructing prop2.


    And, of course, this works as well if the Property stores a pointer instead of the value itself:

    Demo on coliru