Можно ли это сделать с помощью статической типизации?

Этот метод пытается выбрать (std::vector<?>) на основе ключа (std::string), где ? либо int или же float:

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

Решение

Тот факт, что это шаблоны, не имеет к этому никакого отношения.
std::vector<std::vector<int> > а также
std::vector<std::vector<float> > два совершенно не связаны
классы и ведут себя как таковые. Если вам действительно нужно что-то вроде
это, вам придется определить абстрактный базовый класс и два
производные классы, каждый из которых оборачивает соответствующий
std::vector, Но я не понимаю, как вы сможете его использовать, или
даже определить соответствующий абстрактный базовый класс, потому что тип
содержащийся в векторе пронизывает интерфейс. Типы вы
Использование почти в каждом вызове также должно быть различным.

2

Другие решения

Если у вас ограниченное количество вариантов (т. Е. Только вектор с плавающей точкой и вектор типа 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 для определения типа переменной.

2

По вопросам рекламы [email protected]