Подтвердить что ты не робот

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;
}
4b9b3361

Ответ 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);
}