Search code examples
c++staticinitializationconstantsfield

Is there a way to initialize a const static field from another const static field in a different class?


I'm trying to initialize the state of my static const field from (a part of) the state of another const static field from a different class in a different file.

In a simplified example:

// object.h
class Object {
public:
  Object(std::string s) 
    : s(s)
  {}
private:
  std::string s;
};

// a.h
#include "object.h"
class A {
public:
  static const Object o;
};

// a.cpp
#include "a.h"
const Object A::o { "ObjectToCopyFrom" };

// b.h
#include "object.h"
class B {
public:
  static const Object o;
}

// b.cpp
#include "a.h"
const Object B::o { A::o };

In my experience, I found that B::o could not initialize from A::o. It compiles, but the std::string B::o is empty. Am I doing something wrong, or is this simply not possible? Or are there better design strategies for static const fields relying on each other?


Solution

  • From C++17 onwards, you can use inline member variables - in the class declarations - in the respective header files. This avoids the need for definitions of those members in individual source files, thus avoiding any ambiguities related to the order of evaluation of different translation units.

    Also, in the example you've given, you'll need to make the A::o a public member, in order for the B class to use it (class members are private by default).

    Here's a possible 'header-only' solution to your problem:

    // object.h
    #include <string>
    class Object {
    public:
        Object(std::string s_arg) // IMHO, using argument names same as members is not a good idea!
            : s(s_arg)
        { }
    private:
        std::string s;
    };
    
    // a.h
    #include "object.h"
    class A {
    public: // The "o" member MUST be public in order for the initialization in "B" to work!
        static inline const Object o{ "ObjectToCopyFrom" };
    };
    
    // b.h
    #include "a.h" // Need to include the "a.h" header to get the definition of "class A"
    class B {
        static inline const Object o{ A::o };
    };