c++ - 在不同模板化的类型上实现的链表

标签 c++ templates c++11

我已经实现了 Node如下所示的类:

template<unsigned int Size>
class Node
{
    private:
        Eigen::Matrix<float, Size, Size> m_matrix;

        Node<?> *m_previousNode;
        Node<?> *m_nextNode;
};

它有一个成员变量,其维度由模板参数设置。此外,这是重要的部分,它存储指向上一个和下一个节点的指针(其大小可以与其自身的大小不同)。

现在,我有固定数量的此类具有不同大小的节点,我想将它们存储在 Network 中。类(class)。一开始它可能是三维的:

template<unsigned int S0, unsigned int S1, unsigned int S2>
class Network
{
    private:
        Node<S0> *m_firstNode;
        Node<S1> *m_secondNode;
        Node<S2> *m_thirdNode;
};

这是我想要实例化它的方式:

Network<10, 20, 5> network;

如您所见,节点的数量以及每个节点的大小都是固定的;之后无法修改。

我的问题是如何存储指向上一个和下一个节点的指针(上面代码中的 Node<?> *)。

我首先想到像这样扩展模板参数列表:

template<unsigned int PreviousSize, unsigned int Size, unsigned int NextSize>
class Node
private:
    Eigen::Matrix<float, Size, Size> m_matrix;

    Node<?, PreviousSize, Size> *m_previousNode;
    Node<Size, NextSize, ?> *m_nextNode;

但显然,我必须知道前一个节点的前任节点的大小,导致同样的问题——我仍然无法填写 ? .

有什么解决办法吗?

最佳答案

我可以看到几个涉及链表的解决方案,但恐怕它们都很丑陋;)

但是,假设列表的所有节点都属于一个公共(public)实体 Network ,我认为,就是我们的魔法卡。如果我们放弃列表的想法,而是瞄准网络中的“定位”节点,那么它会变得容易得多!

template <typename Network, unsigned Index, unsigned Size>
class Node {
public:

private:
    Network* m_network;
    Eigen::Matrix<float, Size, Size> m_matrix;
}; // class Node

和网络:

template <unsigned Size0, unsigned Size1, unsigned Size2>
class Network {
public:
    template <unsigned Index>
    auto access() -> decltype(m_nodes.get<Index>()) {
        return m_nodes.get<Index>();
    }

    template <unsigned Index>
    auto get() const -> decltype(m_nodes.get<Index>()) {
        return m_nodes.get<Index>();
    }

private:
    std::tuple< Node<Network, 0u, Size0>,
                Node<Network, 1u, Size1>,
                Node<Network, 2u, Size2>> m_nodes;
};

最后,迭代?

template <typename Network, unsigned Index, unsigned Size>
auto Node<Network, Index, Size>::prev() -> decltype(m_network->access<Index-1>()) {
    return m_network->access<Index-1>();
}

template <typename Network, unsigned Index, unsigned Size>
auto Node<Network, Index, Size>::next() -> decltype(m_network->access<Index+1>()) {
    return m_network->access<Index+1>();
}

好吧,除了我们自己遇到了先有鸡还是先有蛋的小问题……我们可以通过嵌套 Node 的定义来欺骗我们的出路。在Network里面类(class)。我可能会这样做,但是,为什么不接受迭代应该始终从网络类开始?

最后,我的建议是:

template <unsigned Size>
class Node {
public:
    // ...
private:
    Eigen::Matrix<float, Size, Size> m_matrix;
};

template <unsigned Size>
std::ostream& operator<<(std::ostream& out, Node<Size> const&) {
    return out << "Node<" << Size << ">";
}

template <unsigned S, unsigned... Sizes>
class Network {
private:
    // Hack for gcc, using m_nodes in decltype requires that it's already been declared
    typedef std::tuple< Node<S>, Node<Sizes>... > Nodes;
    Nodes m_nodes;

public:

    static constexpr unsigned Size() { return sizeof...(Sizes) + 1; }

    template <unsigned Index>
    auto access() -> decltype(std::get<Index>(this->m_nodes)) {
        return std::get<Index>(this->m_nodes);
    }

    template <unsigned Index>
    auto get() const -> decltype(std::get<Index>(this->m_nodes)) {
        return std::get<Index>(this->m_nodes);
    }

}; // class Network

当然,一个Node不再知道它的位置,但你可以将它包装在一个迭代器中:

template <typename Network, unsigned Index>
class NetworkIterator {
private:
    // Hack for gcc, using m_network in decltype requires that it's already been declared
    Network& m_network;

public:
    static_assert(Index < Network::Size(), "Index cannot exceed network size by more than one");

    NetworkIterator(Network& n): m_network(n) {}

    auto element() -> decltype(this->m_network.template access<Index>()) {
        return m_network.template access<Index>();
    }

    template <unsigned U = Index - 1>
    NetworkIterator<Network, U> prev() {
       return NetworkIterator<Network, U>(m_network);
    }

    template <unsigned U = Index + 1>
    NetworkIterator<Network, U> next() {
       return NetworkIterator<Network, U>(m_network);
    }
}; // class NetworkIterator

是的,it works .

关于c++ - 在不同模板化的类型上实现的链表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13895686/

相关文章:

android - Firebase 崩溃报告 - 它现在支持 NDK 吗?

c++ - 使用 pselect 进行同步等待

c++ - 是否允许调用参数中的typename T?

c++ - 结合多种数据类型来制定数据包

c++ - 如何将 std::array C++11 操作转换为 Boost+VS08?

c++ - 给定这两个值的函数会产生第三个值?

c++ - 从控制台读取数据

html - 页眉和页脚之间的中心内容区域

c++ - static_assert 不会立即中断编译

templates - 使用多个管道参数调用模板