views:

97

answers:

3

In C++, I have a certain template function that, on a given condition, calls a template function in another class. The trouble is that the other class requires the full definition of the first class to be implemented, as it creates the second class and stores them and manages them in similar fashions.

The trouble is that naturally, they fall as one class, and thus have some tight interop, except that I need them to be two classes for threading reasons. A sort of, master for all threads, one child per thread, system.

Any advice on how this can be implemented?

Edit@comment: I have a problem that looks a little like this:

class Master {
public:
    Child* CreateChild() {
        return new Child();
    }
    template<typename T> T* GetSomething(int arg) {
        return NULL;
    }
};
class Child {
    Master* master;
    template<typename T> T* GetSomething(int arg) {
        if (arg) return master->GetSomething<T>(arg);
        else return NULL;
    }
};

Those obviously aren't the actual implementations, but similar enough to demonstrate. PIMPL would only help if these were non-template functions, but since they are, then the IMPL needs to be right here.

The Master class manages all the Children (why did I pick Master and Child instead of Parent/Child or Master/Slave?), their memory, lifetimes, etc, and a few other system-wide necessities. But the Child class provides the majority of access and in some cases must fall back to the Master class.

Also, there's no way in hell that I'm going to move to dynamic bindings. The rest of my system already thoroughly abuses dynamic bindings to the absolute max, and I simply can't afford the performance of using them again in this fashion. The Child function in question is called very, very, very often.

A: 

The short answer is: "Move to dynamic bindings."

The long answer. Well, it depends on what exactly you are trying to achieve. But in most cases the PIMPL idiom is usually suitable, but you will have to sacrifice some performance in order to achieve this.

Let_Me_Be
Except that the OP is talking about template classes. In which case PIMPL isn't really suitable.
Job
Yet, it is exactly what was accepted as answer :)
Let_Me_Be
Yes. Strange that he mentioned needing the full definition of the class but accepted an answer using a forward declaration...
Job
+1  A: 

Your best bet is to decouple them as much as possible, and then have the 'child' use only pointers to the 'parent' objects (or vice versa). This might get tricky depending on what you want to do with templates since it requires you to properly separate declarations (header files) from implementations (C files).

Child.h: Don't include Parent.h, instead use a forward declaration (example: class Parent;). Then you can define functions that take or return parent pointers only (no references or instances). You cannot call any Parent member functions or access member variables inside the header.

Parent.h: Include Child.h as normal. No restrictions at all on use of Parent or Child objects in this file.

Parent.cpp and Child.cpp: Include Child.h and Parent.h as normal. No restrictions at all on use of Parent or Child objects in these files.

SoapBox
Yes, but I need to call Parent member functions.
DeadMG
Then do so from a .cpp file.
SoapBox
+2  A: 

For your example, the fact that the classes have a template function makes no real difference; just have a forward reference to the Child class and put the definition of the CreateChild function after the declaration of the Child class:

class Child;
class Master {
public:
    Child* CreateChild() ;
    template<typename T> T* GetSomething(int arg) {
        return NULL;
    }
};

class Child {
public:

    Master* master;
    template<typename T> T* GetSomething(int arg) {
        if (arg) return master->GetSomething<T>(arg);
        else return NULL;
    }
};

Child* Master::CreateChild() {
    return new Child();
}
Pete Kirkham
This worked for me. In Child, instead of storing a Master*, I stored a Master'sInternalVariable*, then declared (but not defined) the constructor to take a Master*, then extracted the pointers from the Master* after the Master was defined.
DeadMG