2010-06-20 7 views
2
struct A 
    { 
    std::string get_string(); 
    }; 

    struct B 
    { 
    int value; 
    }; 

    typedef boost::variant<A,B> var_types; 
    std::vector<var_types> v; 

    A a; 
    B b; 

    v.push_back(a); 
    v.push_back(b); 

Как я могу повторить итерацию через элементы v, чтобы получить доступ к объектам a и b?Как перебирать последовательность ограниченных типов с помощью Boost.Variant

Я могу сделать это с усилением :: получить, но синтаксис очень громоздким .:

std::vector<var_types>:: it = v.begin(); 
while(it != v.end()) 
{ 
    if(A* temp_object = boost::get<A>(&(*it)))  
     std::cout << temp_object->get_string(); 
    ++it; 
} 

Я пытался использовать технику посмотреть недвижимость, но я не слишком далеко и код не работает:

template<typename Type> 
class get_object 
    : public boost::static_visitor<Type> 
{ 
public: 

    Type operator()(Type & i) const 
    { 
    return i; 
    } 

}; 

... 

while(it != v.end()) 
{ 
    A temp_object = boost::apply_visitor(get_object<A>(),*it); 
    ++it; 
} 

EDIT 1

хак решение:

class get_object 
    : public boost::static_visitor<A> 
{ 
public: 

    A operator()(const A & i) const 
    { 
    return i; 
    } 

    A operator()(const B& i) const 
    { 
    return A(); 
    }   
}; 
+0

Так что вы хотите итерацию через объект и для каждого элемента вызова либо функции X или Y, в зависимости от того, если вариант имеет степень А или В? – GManNickG

+0

Да, в значительной степени :) – anno

ответ

1

Edit:
Если это как предполагает UncleBens, то вы можете просто сделать это:

BOOST_FOREACH(var_types& vt, v) { 
    if (vt.which() == 0) 
     cout << get<A>(vt).get_string() << endl; 
} 

Оригинал:
Параметр шаблона для static_vistor является тип возвращаемого из его методов. Это означает, что два класса должны иметь общий тип возврата для одного посетителя. Это должно выглядеть примерно так:

class ABVisitor : public static_visitor<string> { 
public: 
    string operator()(const A& a) const { 
     return a.get_string(); 
    } 
    string operator()(const B& b) const { 
     return lexical_cast<string>(b.value); 
    } 
}; 

Вот пример итерации с использованием этого посетителя.

BOOST_FOREACH(var_types& vt, v) 
    cout << apply_visitor(ABVisitor(), vt) << endl; 
+0

Но разве это не всегда выводит что-то, тогда как в первоначальных попытках что-то было напечатано, только если объект был A? – UncleBens

+0

@UncleBens: ты прав. На этот раз все тело цикла for должно быть у посетителя. –

+0

Как я уже сказал, я знаю, как это сделать с помощью get, но найти синтаксис очень недружелюбно, если я должен разоблачить его через интерфейс класса. – anno

3

Насколько я вижу, посетитель должен выполнять работу. Если вы просто хотите получить сохраненное значение, то boost::get - если я не ошибаюсь - - это предварительно сделанный посетитель для этого.

Пример:

struct print_if_a : boost::static_visitor<void> 
    { 
    void operator()(A& a) const { std::cout << a.get_string() << '\n'; } //alas, get_string is non-const 
    void operator()(const B&) const {} //does nothing, up to optimizer 
    }; 

Использование:

BOOST_FOREACH(var_types& obj, v) { 
    boost::apply_visitor(print_if_a(), obj); 
    } 
+0

Здесь нет необходимости уточнять тип возврата 'boost :: static_visitor', по умолчанию он равен' void', если я не ошибаюсь. –

+0

@Matthieu: Да, вы также можете написать 'boost :: static_visitor <>'. – UncleBens