2012-12-15 30 views
3

我實現了一個Node類,如下所示:鏈表上實現的類型是不同的模板

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

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

它有一個成員變量,其尺寸由模板參數設置。而且,這是重要的部分,它存儲指向前一個和下一個節點的指針(它可以具有與其自身大小不同的大小)。

現在,我有這個類的不同大小的節點,我想要存儲在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; 

但後來,我早就知道前一個節點的前身的大小,從而導致同樣的問題,我還可以」 t填寫?

任何想法如何解決這個問題?

+12

我在這裏出去走走,並建議你可能不想做你認爲你想做的事。模板是編譯時的結構,並不便於運行時檢查。即使您可以構建一些標記聯合類型的小工具或存儲無效指針,您仍然必須在運行時處理結果,這是不切實際的。 –

+0

這個'Size'參數控制着什麼數據結構的大小?你是說每個節點的大小不同,它不是一個列表中所有節點的常量? –

+0

也許術語»鏈接列表«是誤導性的。我想用固定數量的節點(每個節點常量,每個節點具有另一個大小值)來設置列表。編譯時已知節點的數量和大小。 – wuschelhase

回答

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>(); 
} 

好了,除了我們現在看到自己有點雞和蛋的問題......我們可以出,雖然通過嵌套Network類中的Node定義騙我們的方式。然而,我可能會這麼做,爲什麼不接受迭代應該始終從網絡類開始?

最後,這裏是我的建議:

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