简体   繁体   中英

passing a variable as template argument

I have a template node class that takes an integer parameter. I also have a tree class that creates a node and passes its constructor argument as the argument for the node template.

Tree.cpp

Tree::Tree(int n) {
    this->n = n;
    root = new Node<n>(); // compiler error
}

main.cpp

Tree *tree = new Tree(2);

My compiler complains that 'n' is not a constant expression . How do I successfully pass n to my node class?

I don't think you can do like that.

n is known at compile time, but it is not known as a template argument. Since you need n in your Tree constructor, you could make your Tree class a template too.

Make your constructor a template one:

struct Base
{

};
template <int N>
struct Node : Base
{

};

class Tree 
{
public:

    template <int N>
    struct size
    {
    };

    template<int N> Tree(size<N>) {
        this->n = N;
        root = new Node<N>();
    }

    int n;
    Base* root;
};

int main() {

    Tree t = Tree(Tree::size<2>());

    return 0;
}

The way you did it cannot work, for n must be known at compile-time.
You can make it a constructor template parameter. Unfortunately, in this case, it cannot be explicitly given and must be deducible. It's a matter of an ugly syntax that works anyway.
It follows a minimal, working example:

#include<type_traits>

struct BaseNode {};

template<int n>
struct Node: BaseNode {};

struct Tree {
    template<int n>
    Tree(std::integral_constant<int, n>)
        : n{n}, root{new Node<n>()}
    {}

    int n;
    BaseNode *root;
};

int main() {
    Tree tree{std::integral_constant<int, 2>{}};
}

Note that you can easily work around the ugly syntax with a factory method:

struct Tree {
    template<int n>
    Tree(std::integral_constant<int, n>)
        : n{n}, root{new Node<n>()}
    {}

    template<int n>
    static Tree create() {
        return Tree{std::integral_constant<int, n>{}};
    }

    int n;
    BaseNode *root;
};

// ...

Tree tree = Tree::create<2>();

Another possible solution is to provide a Node as an argument and deduce n from it:

struct Tree {
    template<int n>
    Tree(Node<n> *node)
        : n{n}, root{node}
    {}

    // ...
};

Or use a two steps initialization and be able to explicitly pass your n as a template parameter:

struct Tree {
    Tree(): n{0}, root{nullptr} {}

    template<int n>
    void init() {
        this->n = n;
        root = Node<n>;
    }

    int n;
    BaseNode *root;
};

// ...

Tree tree{};
tree.init<2>();

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