我已经实现了一个Node
类,如下所示:
template<unsigned int Size>
class Node
{
private:
Eigen::Matrix<float, Size, Size> m_matrix;
Node<?> *m_previousNode;
Node<?> *m_nextNode;
};
它有一个成员变量,其大小由template参数设置。此外,这是重要的部分,它存储指向上一个和下一个节点的指针(可以具有与其自身大小不同的大小)。
现在,我有一个固定数量的节点,这个节点有不同的大小我想要存储在Network
类中。开头可能是三维的:
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;
但显然,我必须知道前一个节点的前身的大小,导致同样的问题 - 我仍然无法填写?
。
任何想法如何解决这个问题?
答案 0 :(得分:0)
我可以看到几个涉及链接列表的解决方案,但它们都是,我担心,但是很丑陋;)
但是,鉴于列表中的所有节点都属于公共实体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
的定义来欺骗我们的出路。我可能会这样做,但是,为什么不接受迭代应始终从网络类开始?
最后,我的建议如下:
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。