2013-02-07 59 views
0

此方法試圖選擇一個(std::vector<?>)的基礎上的鍵(std::string),其中?要麼intfloat這可以通過靜態類型來完成嗎?

template<typename L> 
inline void EnsembleClustering::Graph::forNodesWithAttribute(std::string attrKey, L handle) { 
    // get nodemap for attrKey 

    auto nodeMap; // ? 

    auto findIdPair = this->attrKey2IdPair.find(attrKey); 
    if (findIdPair != this->attrKey2IdPair.end()) { 
     std::pair<index, index> idPair = findIdPair->second; 
     index typeId = idPair.first; 
     index mapId = idPair.second; 

     // nodemaps are in a vector, one for each node attribute type int, float, NodeAttribute 
     switch (typeId) { 
     case 0: 
      nodeMap = this->nodeMapsInt[mapId]; 
      break; 
     case 1: 
      nodeMap = this->nodeMapsFloat[mapId]; 
      break; 
     } 

     // iterate over nodes and call handler with attribute 
     this->forNodes([&](node u) { 
      auto attr = nodeMap[u]; 
      handle(u, attr); 
     }); 
    } else { 
     throw std::runtime_error("node attribute not found"); 
    } 

} 

類的相關部件是:

std::map<std::string, std::pair<index, index>> attrKey2IdPair; // attribute key -> (attribute type index, attribute map index) 

// storage 
std::vector<std::vector<int> > nodeMapsInt;   // has type id 0 
std::vector<std::vector<float> > nodeMapsFloat;  // has type id 1 

這將不會編譯,因爲auto nodeMap(= std::vector<?>)未初始化。但爲了初始化它,我必須在編譯時知道它的類型。

也許我正在嘗試使用靜態類型無法完成。有沒有一種C++的方式來實現這一點?

+0

您不能在運行時選擇類型,否。 'auto'仍然只能在編譯時運行。但是,您可以編寫兩個不同的函數,並根據字符串調用正確的函數。 –

+0

@BoPersson但是可能的字符串(鍵)在編譯時並不知道。你腦子裏還在想着什麼? – clstaudt

+0

看起來像你在「int」和「float」之間選擇。只需爲每個變體編寫一個函數,然後調用所需的函數。 –

回答

2

這些都是模板的事實與它無關。 std::vector<std::vector<int> >std::vector<std::vector<float> >是兩個完全不相關的類,並且表現如此。如果你真的需要類似 這個,你必須定義一個抽象基類和兩個派生類,每個類包裝相應的 std::vector。但我不明白你將如何使用它,或者甚至定義一個合適的抽象基類,因爲矢量中包含的類型 滲透到界面。幾乎在每次通話中您使用的類型也必須不同。

2

如果變量的數量有限(即只有float的向量和int的向量),則可以使用boost::variant來存儲它。

定義變異的類型,並定義遊客結構:

#include "boost/variant.hpp" 

//Define type 
typedef boost::variant<std::vector<int>, std::vector<float>> VectorType; 

struct VectorTypeVisitor : public boost::static_visitor<void> 
    { 
     node& m_u; 

     VectorTypeVisitor(node& u) : m_u(u) { } //Pass node to visitor in constructor 

     void operator()(const std::vector<int>& nodeMap) const 
     { 
      auto attr = nodeMap[m_u]; 
      handle(m_u, attr); 
     } 

     void operator()(const std::vector<float>& nodeMap) const 
     { 
      auto attr = nodeMap[m_u]; 
      handle(m_u, attr); //What to do if visitor applied to float 
     } 
    } 

那麼您的代碼可能看起來像:

template<typename L> 
inline void EnsembleClustering::Graph::forNodesWithAttribute(std::string attrKey, L handle) { 
    // get nodemap for attrKey 

    VectorType nodeMap; 

    auto findIdPair = this->attrKey2IdPair.find(attrKey); 
    if (findIdPair != this->attrKey2IdPair.end()) { 
     std::pair<index, index> idPair = findIdPair->second; 
     index typeId = idPair.first; 
     index mapId = idPair.second; 

     // nodemaps are in a vector, one for each node attribute type int, float, NodeAttribute 
     switch (typeId) { 
     case 0: 
      nodeMap = this->nodeMapsInt[mapId]; 
      break; 
     case 1: 
      nodeMap = this->nodeMapsFloat[mapId]; 
      break; 
     } 

     // iterate over nodes and call handler with attribute 
     this->forNodes([&](node u) { 
      boost::apply_visitor(VectorTypeVisitor(u), nodeMap); 
     }); 
    } else { 
     throw std::runtime_error("node attribute not found"); 
    } 
} 

但是,它仍然不好傳遞變量一樣的typeid識別變量類型。