Является ли класс посетителя boost::variant обязательным?

Должен ли я использовать класс посетителя, такой как class Visitor : public boost::static_visitor<>, с boost::variant?

Если нет, то есть ли причины не использовать посетителя? Есть ли причины предпочесть класс посетителей?

Я задаю этот вопрос, потому что класс посетителя кажется избыточным аспектом использования boost::variant.


person Mushy    schedule 03.04.2013    source источник


Ответы (2)


Вы не обязаны использовать посетителя, вы можете запросить базовый тип, используя get<T>().

Это приводит к такому коду:

int foo(boost::variant<int, std::string, Bar> const& v) {
    if (int const* i = get<int>(&v)) {
        return *i;
    }
    if (std::string const* s = get<std::string>(&v)) {
        return boost::lexical_cast<int>(*s);
    }
    if (Bar const* b = get<Bar>(&v)) {
        return b->toInt();
    }

    std::abort(); // ?
}

Что, возможно, уродливо... и, кроме того, имеет проблему, заключающуюся в том, что если вы добавите один тип к варианту, вам вдруг понадобится проверить каждое его использование в коде, чтобы убедиться, что вы не пропустили где-то if.

С другой стороны, если вы используете вариант, если вам когда-либо не удастся обработать случай (тип), вы получите уведомление с ошибкой времени компиляции.

На мой взгляд, использование boost::static_visitor бесконечно лучше... хотя я пару раз использовал альтернативу get<T>(); обычно, когда мне нужно проверить только один (или два) типа и не заботиться (вообще) обо всех остальных. Альтернативой может быть использование посетителя с перегрузкой template <typename T> void operator()(T const&) const;, что не обязательно чище.

person Matthieu M.    schedule 03.04.2013
comment
Могу ли я просто запросить базовый тип, используя SomeVariantVariable.which(), который вернет индекс для объявления typedef boost::variant<Type1, Type2> variant_variable и укажет, какой тип: Type1 = 0, Type2 = 1? - person Mushy; 03.04.2013
comment
@Mushy: вы можете да, а затем switch на этом и позвоните get(); но в этот момент вы просто переопределяете код, вызывающий посетителя... за исключением того, что если кто-то добавит тип в середину списка, тогда индексы сместятся, и, таким образом, get() может вернуть нуль, который вы должны учитывать (или сбой ). - person Matthieu M.; 03.04.2013

Если вы хотите выполнить какую-либо операцию над вариантом, например, некоторую проверку, вы можете захотеть иметь его как посетителя.

struct to_str : boost::static_visitor<std::string>
{
   template<class T>
   std::string operator()(T const & x) const
   {
      return boost::lexical_cast<std::string>(x);
   }
};

С другой стороны, если вы хотите, например, проверить, является ли он int, и что-то с ним сделать, вы, вероятно, использовали бы boost::get, например.

if(const int * my_int = boost::get<int>(&my_var)) //no-throw form
{
  //do smth with int
}
person kassak    schedule 03.04.2013