mardi 29 mars 2016

Circular dependency in templated inheritance hierarchy

I have a templated Base class that has multiple child classes and provides an abstract execute method. The children implement this method in different manners and may delegate execute calls to objects in the tail vector of the Base class. In order to chain objects to the tail, the Base class provides some methods (createChild1, createChild2). Here is the code:

base.h

#pragma once

#include <memory>
#include <vector>

template<typename T>
class Child1;

template<typename T>
class Child2;

template<typename T>
class Base {
public:
    std::vector<std::unique_ptr<Base<T>>> tail;

    virtual void execute(const T &t) = 0;

    Base<T> &createChild1() {
        auto child = std::make_unique<Child1<T>>();
        tail.push_back(std::move(child));
        return *tail.back().get();
    }

    Base<T> &createChild2() {
        auto child = std::make_unique<Child2<T>>();
        tail.push_back(std::move(child));
        return *tail.back().get();
    }
};

child1.h

#pragma once

#include "base.h"

template<typename T>
class Child1 : public Base<T> {
public:
    virtual void execute(const T &t) {
        // do something with t
    }
};

child2.h

#pragma once

#include "base.h"

template<typename T>
class Child2 : public Base<T> {
public:
    virtual void execute(const T &t) {
        // do something with t
        // then delegate to t
        for (auto &next : tail) {
            next->execute(t);
        }
    }
};

main.cpp

#include <iostream>

#include "child1.h"

using namespace std;

int main(int argc, char **argv) {
    Child1<int> c;
    c.createChild2().createChild1();
    c.execute(10);
    return 0;
}

If I try to compile, I get a "implicit instantiation of undefined template 'Child2'" because in Base, the template class Child2 is only forward declared and its body is not known at that moment. Forward declaring Base in front of Child1 and Child2 and including the definitions of Child1 and Child2 in Base does not solve the problem, because then Child2 cannot access tail. How can I solve this circular dependency? The code in Child1, Child2 and Base can change, but I want to keep the possibility to chain the create calls in main (therefore the create methods must be declared in the Base class).

Aucun commentaire:

Enregistrer un commentaire