Class A is the sole instantiator and container of instances of class B.
So it seemed like a good idea to make the constructor of class B private, and call it only by a friend function declared in class B and defined in class A.
File A.h (EDIT: included enum defined in class B)
#ifndef   A_H
#define   A_H
#include "B.h"
using namespace std;
class A
{   public:
    A();
    shared_ptr<B> CreateBInstance( const B::ENUM_STANDARD_COLORS );
    shared_ptr<B> CreateBInstance( const string );  // Custom color
    private:
    unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
}
#endif
File B.h (EDIT: included enum defined in class B)
#ifndef   B_H
#define   B_H
#include "A.h"  // Causes chaos
using namespace std;
class B
{   public:
    enum class ENUM_STANDARD_COLORS : unsigned int
    {   ...     // ~70 standard colors
    };
    private:
    B();
    friend
    shared_ptr<B> A::CreateBInstance( const ENUM_STANDARD_COLORS );
    friend
    shared_ptr<B> A::CreateBInstance( const string );   // Custom color
}
#endif
Class A requires a full declaration (#include) of class B for shared_ptr<B>.
Class B requires some declaration of class A for the friend function.
A simple forward declaration causes the error:
invalid use of incomplete type 'struc A'
at the friend function declaration.
A full declaration (#include) is far worse:
error: prototype for 'std::shared_ptr A::CreateInstance()' does not match any in class 'A'
(but it does!) at the friend function declaration.
And, because class B is now broken:
error: 'B' was not declared in this scope
error: template argument 1 is invalid
appears at every mention of B in class A, as well as in classes F and G (etc.) which #include class B for their own use of shared_ptr<B>.
And, because classes F and G are also now broken:
error: 'F' was not declared in this scope
error: template argument 1 is invalid>
error: 'G' was not declared in this scope
error: template argument 1 is invalid
appears at every mention of F and G in class A.
Unfortunately, the include guards don't prevent the circular inclusion.
Is there a way to make this friend function work? I've never achieved so many errors in one go!
Class
Arequires a full declaration (#include) of classBforshared_ptr<B>.
No, forward declaration would be sufficient in A.h. shared_ptr (and unique_ptr) won't require class B to be complete type for return type declaration[1] and class data member declaration.
File A.h
#ifndef   A_H
#define   A_H
class B;  // forward declaration
using namespace std;
class A
{   public:
    A();
    shared_ptr<B> CreateBInstance();
    private:
    unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
};
#endif
[1] It's also true for "regular" type T which isn't shared_ptr.
In A header file, you can simply tell the compiler that an type B exists and it needs to look for it while linking. To do so, replace
#include "B.h" 
by
class B;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With