简体   繁体   中英

C++: 2 templates vs. 1 template specialization on complex class

I have a custom rather complex data structure with this form:

class Root;

class Tree {

public:
    ... // lots of members here, child access etc
    ExactBar *bar() { return mBar; }
    ExactQux *qux() { return mQux; } 
private:
    ... // lots of members here
    ExactBar *mBar;
    ExactQux *mQux;
};

class Root : public Tree { // root manages the memory for all tree nodes!
    ...
private:
    MemorySpace<Tree> mNodes;
    MemorySpace<ExactBar> mBars;
    MemorySpace<ExactBar> mQuxs;
};

The purpose of the program is to build the tree for which it requires the exact types above. This requires massive amounts of memory and I'm literally stretched to the 32-bit limit. So I want to, once the tree is built, convert the whole tree to an inexact type which is not only faster, but takes much less memory.

But of course I would like to keep the functionality that Tree offers with its methods, and of course other algorithms that work on Tree . So writing a new class is out of the question. So templates seem very appropriate here. However, I'm wondering about two ways of writing the new, templated class. One obvious way is

template <typename Bar, typename Qux> class Tree {

public:
    ... // lots of members here, child access etc
    Bar *bar() { return mBar; }
    Qux *qux() { return mQux; } 
private:
    ... // lots of members here
    Bar *mBar;
    Qux *mQux;
};

template <typename Bar, typename Qux> class Root : public Tree<Bar, Qux> {
    ...
private:
    MemorySpace<Tree> mNodes;
    MemorySpace<Bar> mBars;
    MemorySpace<Qux> mQuxs;
};

However this definition seems a bit awkward. I mean, I know I will never use Tree<InexactBar, ExactQux> for instance. Is this bad practice? Sure, you can also solve the long name with a typedef but still. Another solution I thought about is this:

template <typename Exactness> class Tree;

template <> class Tree<Exact> {

public:
    ... // lots of members here, child access etc
    ExactBar *bar() { return mBar; }
    ExactQux *qux() { return mQux; } 
private:
    ... // lots of members here
    ExactBar *mBar;
    ExactQux *mQux;
};
// ... similar for Inexact

Which method is preferable, are there any patterns or anti-patterns or ripple effects doing this that I should be aware of? Thanks!!

Here's another option, that minimizes the number of template parameters and the amount of duplicated code:

struct Exact
{
    typedef ExactBar BarType;
    typedef ExactQux QuxType;
};

struct Inexact
{
    typedef InexactBar BarType;
    typedef InexactQux QuxType;
};

template <typename Exactness> class Tree {

public:
    typedef typename Exactness::BarType Bar;
    typedef typename Exactness::QuxType Qux;

    ... // lots of members here, child access etc
    Bar *bar() { return mBar; }
    Qux *qux() { return mQux; } 
private:
    ... // lots of members here
    Bar *mBar;
    Qux *mQux;
};

This is similar to policy-based design . Of course you still have to templatize all your other functions that deal with the Tree type, so there's still a ripple effect. Although you could partially dodge the ripple effect like so:

template <typename Exactness> class TTree {
    ... // lots of members
};

typedef TTree<Exact> Tree; // same name as before!
typedef TTree<Inexact> InexactTree;

Another option in addition to @John's is to do explicit instantiation of your template. That is, do not include the template code into your header, but include it in a separate .cpp , and add there an explicit lines on what types do you instantiate with:

template class Tree<ExactBar, ExactQux>;
template class Tree<InexactBar, InexactQux>;

This way the compiler will not link any code using any other instantiation.

If you are pretty sure that these are the only instantiations you would ever need, then this has an additional advantage of decreased compilation time. However, this makes extending the code more difficult: you will have to modify the same .cpp if you want to add new instantiations. This is why I would suggest you using this only if you are pretty sure that you will have the full control on possible instantiations and that the number of this instantiations will not be large.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM