Кортежи неизвестного размера / типов параметров
-
19-09-2019 - |
Вопрос
Мне нужно создать карту, от целых чисел до наборов кортежей, кортежи в одном наборе имеют одинаковый размер.Проблема в том, что размер кортежа и типы его параметров могут быть определены во время выполнения, а не во время компиляции.Я представляю себе что-то вроде:
std::map<int, std::set<boost::tuple> >
но не совсем уверен, как именно это сделать, властно используя указатели.
Целью этого является создание временных связей (таблиц), каждая из которых имеет уникальный идентификатор (ключ), возможно, у вас есть другой подход.
Решение
Цель boost::tuple
заключается в смешивании произвольных типов.Если, как вы говорите,
Я вставляю только целые числа
тогда вам следует использовать map< int, set< vector< int > > >
.(На твоем месте я бы бросил немного typedef
s при этом.)
Однако, чтобы ответить на первоначальный вопрос, boost::tuple
не допускает произвольных типов во время выполнения. boost::any
делает.Однако, any
не поддерживает сравнение, поэтому потребуется немного больше работы, если вы хотите использовать его в set
.
typedef vector< boost::any > tuple;
struct compare_tuple { bool operator()( tuple const &l, tuple const &r ) const {
assert ( l.size() == r.size() );
for ( tuple::iterator lit = l.begin(), rit = r.begin();
lit != l.end(); ++ lit, ++ rit ) {
assert ( lit->type() == rit->type() );
if ( lit->type() == typeid( foo ) ) { // find the type and perform "<"
return boost::any_cast<foo>(*lit) < boost::any_cast<foo>(*rit);
} else if ( lit->type() == typeid( bar ) ) {
return boost::any_cast<bar>(*lit) < boost::any_cast<bar>(*rit);
} /* etc; you will need to enumerate all the types you can insert */
}
} };
typedef std::map< int, std::set< tuple, compare_tuple > > main_map;
Другие советы
В качестве современного примечания (поскольку предыдущие ответы относятся примерно к 2010 году), для этого были бы полезны сегодняшние шаблоны Variadic:
template<typename... Args> //Accept any number of arguments and types
auto MyFunction(std::tuple<Args...> &T)->void
{
//Do stuff...
}
Вы можете хранить эти разные наборы в одной коллекции, только если у вас есть какой-то общий базовый класс для них.Вы могли бы написать абстрактный интерфейс, а затем реализовать его для каждого типа таблицы / кортежа.Проблема в том, что обычно такие интерфейсы имеют тенденцию быть очень запутанными, и у вас, возможно, произошел бы взрыв класса, если бы у вас было много типов таблиц / кортежей. Повышение.Любое может быть полезно для такого интерфейса (поскольку вам приходится динамически обрабатывать разные типы данных).
Если типы параметров имеют что-то общее, перенесите это в абстрактный базовый класс и сделайте так, чтобы кортеж содержал указатели на этот базовый класс:
class MyParamBase {
public:
virtual int getFoo() = 0;
virtual void setFoo(int) = 0;
};
std::map<int, std::set<MyParamBase*> > container;
(boost::кортеж опущен для краткости.Не уверен, зачем вам нужен набор кортежей.)
Затем вы можете получить конкретные типы параметров из MyParamBase, создать и вставить их в map:
class SomeParam: MyParamBase {
public:
virtual int getFoo() { ... }
virtual void setFoo(int a) { ... }
};
std::set<MyParamBase*> some_set;
some_set.insert(new SomeParam());
container[123] = some_set;
Если типы параметров не имеют ничего общего - не помещайте их в одну и ту же карту.Вполне вероятно, что они не принадлежат друг другу.