VermillionAzure VermillionAzure -4 years ago 106
C++ Question

How to organize includes for a header-only library that wants to expose mutually recursive functions?

I'm creating a library such that there are functions that look like this:

template <typename T> bool A (int, int, T&);
template <typename T> bool B (int, int, T&);

template <typename T>
class IFoo {
virtual T funct(int i) = 0;
};

template <typename T>
class FooA : IFoo<T> {
virtual T funct(int i) override {
if (!i) {
return FooB(i-1);
} else {
return T(0);
}
}
};

template <typename T>
class FooB : IFoo<T> {
virtual T funct(int i) override {
if (!i) {
return FooA(i-1);
} else {
return T(1);
}
}
};


These definitions require splitting up the code into declaration and definition parts so as to allow both procedures to be aware of each other, and then have access to implementations at the same time.

But my question is, how can I expose these functions in a clear manner (meaning, how should I write a header to encapsulate the dependency include pattern) while also making it easy to add new "functions" or other mutually recursive components (meaning, functions or derived classes) so that users of the components will not have to manually order the include of the declaration headers and the definition headers?

Answer Source

By separating declarations from implementations.

template <typename T>
class IFoo {
    virtual T funct(int i) = 0;
};

template <typename T>
class FooA : IFoo<T> {
    virtual T funct(int i) override;  // declaration only...
};

template <typename T>
class FooB : IFoo<T> {
    virtual T funct(int i) override {
        if (!i) {
            return FooA<T>(i-1);
        } else {
            return T(1);
        }
    }
};


// implementation here - once all type information is available
template<typename T>
T FooA<T>::funct(int i) {
    if (!i) {
        return FooB<T>(i-1);
    } else {
        return T(0);
    }
}

how to organise headers?

Here's one way:

detail/ifoo.hpp

#pragma once
template <typename T>
class IFoo {
    virtual T funct(int i) = 0;
};

detail/fooa.hpp

#pragma once
#include "ifoo.hpp"

template <typename T>
class FooA : IFoo<T> {
    virtual T funct(int i) override;
};

detail/foob.hpp

#pragma once
#include "ifoo.hpp"

template <typename T>
class FooB : IFoo<T> {
    virtual T funct(int i) override;
};

detail/impl_fooa.hpp

#pragma once
#include "fooa.hpp"
#include "foob.hpp"
template<typename T>
T FooA<T>::funct(int i) {
    if (!i) {
        return FooB<T>(i-1);
    } else {
        return T(0);
    }
}

detail/impl_foob.hpp

#pragma once
#include "fooa.hpp"
#include "foob.hpp"
tempalte<typename T>
virtual T FooB<T>::funct(int i) override {
    if (!i) {
        return FooA<T>(i-1);
    } else {
        return T(1);
    }
}

finally your header

library.hpp

#pragma once

#include "detail/ifoo.hpp"
#include "detail/fooa.hpp"
#include "detail/foob.hpp"
#include "detail/impl_fooa.hpp"
#include "detail/impl_foob.hpp"
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download