Boost Variant: как получить в настоящее время проводимый тип? - PullRequest
41 голосов
/ 01 декабря 2011

Как я понял, все типы boost.variant разбиты на реальные типы (имеется в виду, что boost variant<int, string> a; a="bla-bla" после компиляции превратится в string a; a="bla-bla") И поэтому мне интересно: как получить тип был введен в буст-вариант?

Что я пробовал:

#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;
}

Ответы [ 3 ]

32 голосов
/ 01 декабря 2011

v.which() вернет основанный на 0 индекс типа объекта, который в настоящее время удерживается.

Когда вы извлекаете объект, ваш код должен использовать статический тип (для того, чтобы удовлетворить get<T>шаблон функции) для ссылки на (эффективно) динамически типизированный объект.

Вам необходимо либо проверить тип (используя which() или type()) и выполнить ветвление соответственно, либо использовать статический посетитель.Независимо от того, какой путь вы выберете, вы должны явно указать статический тип, который вы хотите получить, и он должен соответствовать динамическому типу, иначе будет выдано исключение.

Одним из способов решения этой проблемы является вместо использованиятип варианта напрямую, используйте класс, который содержит тип варианта внутри, а затем определяет любые неявные операторы преобразования, необходимые для использования объекта с минимальной суетой.

У меня есть проект с именем Dynamic C ++ , которыйиспользует эту технику.

18 голосов
/ 01 декабря 2011

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;
10 голосов
/ 12 ноября 2013

Вы можете использовать следующее, что приведет к объектам std :: type_info:

  • функция-член type () в boost :: variable,
  • оператор C ++ 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);
}
...