2013-06-26 1 views
1

Я пытаюсь решить следующую проблему. У меня есть вектор (на самом деле это настраиваемая структура, но вектор является достаточно хорошей заменой этой проблеме) указателей на пользовательский класс A. Класс A может фактически хранить указатель type_a или указатель type_b (эти типы совершенно разные и не связаны друг с другом). Прямо сейчас это реализовано путем сохранения обоих параметров, установив их на NULL, а затем с букетом if/else утверждений, чтобы проверить, какой тип он является, и выполнить соответствующие действия.Вариантное переменное взаимодействие с невариантным типом

class A { 
public: 
    A() : p1(NULL), p2(NULL) {} 

    type_a * p1; 
    type_b * p2; 
}; 

std::vector<A *> v; 

... 

if (v[0]->p1 != NULL) { /* do this */ } 
else if (v[0]->p2 != NULL) { /* do that */ } 

Я планирую добавить больше указателей на класс A и так выше, начинает становиться хлопот. Решение, которое я в настоящее время пытаюсь сделать работу использует boost::variant вместо того, чтобы иметь:

class A { 
public: 
    boost::variant<type_a*, type_b*> p; 
}; 

Проблемы я столкнулся, хотя, является то, что один из моих действий включает вызов функции, которая будет присваивать некоторые значения к переменная в зависимости от типа p У меня есть. Это то, что сейчас и соответствующая process_stuff функция вызывается в одном из приведенных выше утверждений if/else:

class B { /*...*/ }; 

void process_stuff(type_a * p, B * b) { 
    b->m_var = p->fn1(); 
} 

void process_stuff(type_b * p, B * b) { 
    b->m_var = p->fn2(); 
} 

Я не могу получить эту работу с boost::static_visitor, так как (насколько я понимаю) я не могу имеют невариантный тип в качестве аргумента при двоичном посещении, а также я не могу создать константу operator(), чтобы сделать вторую переменную членом класса посетителя и изменить ее внутри operator() с унаследованным посещением. Поэтому я смущен, как преобразовать вышеуказанную функцию process_stuff, чтобы играть вместе с boost::variant.

Btw Я не привязан к boost::variant и принимал другие решения.

+0

Короткий ответ: если вы не можете каким-либо образом объединить типы, как вы делаете гетерогенную коллекцию, это, вероятно, будет уродливым и неуклюжим. –

+0

К сожалению, я не могу унифицировать типы. Я думаю, что все это сработало бы неплохо, если бы я мог, например. имеют не-const 'operator()' в 'static_visitor'. – eddi

ответ

4

Вам просто нужен посетитель с постоянным статусом. Я печатаю это из неопределенной памяти о том, как выглядят посетители, но вы можете исправить любые ошибки, которые я совершаю.

class process_stuff_visitor : public boost::static_visitor<void> { 
    B* m_b; 

public: 
    process_stuff_visitor(B* b) : m_b(b) {} 
    void visit(type_a* a) const { m_b->m_var = a->fn1(); } 
    void visit(type_b* b) const { m_b->m_var = b->fn2(); } 
}; 
// actual processing: 
boost::apply_visitor(v[0], process_stuff_visitor(the_b)); 

В качестве альтернативы, поскольку вы назначаете один и тот же член B, вы можете просто извлечь генерирующую ценность часть.

struct generate_stuff_visitor : public boost::static_visitor<TypeOfMVar> { 
    TypeOfMVar visit(type_a* a) const { return a->fn1(); } 
    TypeOfMVar visit(type_b* b) const { return b->fn2(); } 
}; 
the_b->m_var = boost::apply_visitor(v[0], generate_stuff_visitor()); 
0

Очень общий объектно-ориентированный способ делать то, что вы хотите сделать (если я правильно вас понимаю), - создать виртуальный базовый класс для типов a и b (и любых других типов, которые вы хотите), который определяет чистый виртуальный метод. Этот метод будет возвращать что-то другое для каждого типа (например, метод type_b :: может возвращать «b», тогда как метод type_a :: может возвращать «a»), поэтому, когда вы вызываете метод вашего неуказанного типа, вам будет сказано какой это тип.

Оттуда вы можете использовать возвращаемое значение метода идентификации, чтобы быть субъектом оператора switch или какой-либо другой традиционной структуры управления, чтобы вызвать правильное поведение.

+0

Спасибо, но 'type_a' и' type_b' являются «богом», поэтому я не могу контролировать их. – eddi

+0

А, в таком случае я бы согласился с оценкой ситуации Джерри Коффином. – CosmicComputer