Boost Variant: как получить текущий тип?
Как я понял, все типы boost.variant анализируются на реальные типы (что означает, что boost variant<int, string> a; a="bla-bla"
после компиляции превратится в string a; a="bla-bla"
) И поэтому я задаюсь вопросом: как получить, какой тип был введен в вариант boost?
Что я пробовал:
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
int main()
{
typedef boost::function<double (double x)> func0;
typedef boost::function<double (double x, double y)> func1;
typedef boost::variant<int, func0, func1> variant_func;
func1 fn = std::plus<double>();
variant_func v(fn);
std::cout << boost::get<func1>(v)(1.0, 1.0) << std::endl; // this works
//std::cout << boost::get<v::type>(v)(1.0, 1.0) << std::endl; // this does not compile with many errors
// std::cout << (v)(1.0, 1.0) << std::endl; // this fails with Error 1 error C2064: term does not evaluate to a function taking 2 arguments
std::cin.get();
return 0;
}
Ответы
Ответ 1
v.which()
вернет индекс, основанный на 0, типа объекта, который в данный момент находится.
Когда вы извлекаете объект, ваш код должен использовать статический тип (чтобы удовлетворить шаблон функции get<T>
), чтобы ссылаться на (эффективно) динамически типизированный объект.
Вам нужно либо проверить тип (используя which()
, либо type()
), либо вступить в ветки или использовать статического посетителя. Независимо от того, каким образом вы выбираете, вы должны явно указать статический тип, который хотите получить, и он должен соответствовать динамическому типу, или будет выбрано исключение.
Один из способов решения этой проблемы заключается в том, чтобы использовать тип варианта напрямую, использовать класс, который содержит тип варианта внутри, а затем определяет любые неявные операторы преобразования, необходимые для использования объекта с минимальной суматохой.
У меня есть проект под названием Dynamic С++, который использует эту технику.
Ответ 2
boost.variant
имеет функцию .type()
, которая может возвращать typeid активного типа, если вы включили RTTI.
Вы также можете определить статического посетителя для выполнения действий в зависимости от типа содержимого варианта, например.
struct SomeVisitor : public boost::static_visitor<double>
{
double operator()(const func0& f0) const { return f0(1.0); }
double operator()(const func1& f1) const { return f1(1.0, 1.0); }
double operator()(int integer) const { return integer; }
};
...
std::cout << boost::apply_visitor(SomeVisitor(), v) << std::endl;
Ответ 3
Вы можете использовать следующие, которые приводят к объектам std:: type_info:
- функция type() члена boost:: variant,
- оператор С++ typeid(), который может применяться к любому типу или типизированному выражению,
вместе с функцией-членом std:: type_info:: operator ==, чтобы проверить, какой тип в данный момент хранится в boost:: варианте. Например,
boost::variant<int, bool, std::string> container;
container = "Hello world";
if (container.type() == typeid(std::string)) {
std::cout << "Found a string: " << boost::get<std::string>(container);
}
else if (container.type() == typeid(int)) {
std::cout << "Found an int: " << boost::get<int>(container);
}