2010-05-15 1 views
4
// ... snipped includes for iostream and fusion ... 
namespace fusion = boost::fusion; 

class Base 
{ 
protected: int x; 
public: Base() : x(0) {} 
    void chug() { 
     x++; 
     cout << "I'm a base.. x is now " << x << endl; 
    } 
}; 

class Alpha : public Base 
{ 
public: 
    void chug() { 
     x += 2; 
     cout << "Hi, I'm an alpha, x is now " << x << endl; 
    } 
}; 

class Bravo : public Base 
{ 
public: 
    void chug() { 
     x += 3; 
     cout << "Hello, I'm a bravo; x is now " << x << endl; 
    } 
}; 

struct chug { 
    template<typename T> 
    void operator()(T& t) const 
    { 
     t->chug(); 
    } 
}; 

int main() 
{ 
    typedef fusion::vector<Base*, Alpha*, Bravo*, Base*> Stuff; 
    Stuff stuff(new Base, new Alpha, new Bravo, new Base); 

    fusion::for_each(stuff, chug());  // Mutates each element in stuff as expected 

    /* Output: 
     I'm a base.. x is now 1 
     Hi, I'm an alpha, x is now 2 
     Hello, I'm a bravo; x is now 3 
     I'm a base.. x is now 1 
    */ 

    cout << endl; 

    // If I don't put 'const' in front of Stuff... 
    typedef fusion::result_of::push_back<const Stuff, Alpha*>::type NewStuff; 

    // ... then this complains because it wants stuff to be const: 
    NewStuff newStuff = fusion::push_back(stuff, new Alpha); 

    // ... But since stuff is now const, I can no longer mutate its elements :(
    fusion::for_each(newStuff, chug()); 

    return 0; 
}; 

Как мне получить for_each (newStuff, chug()) для работы?Что такое правильное использование boost :: fusion :: push_back?

(Примечание. Я только при условии, из overly brief documentation на буст :: фьюжн, что я должен создать новый вектор каждый раз, когда я называю push_back)

ответ

1

(Примечание: Я только при условии, из чрезмерно короткой документации по boost :: fusion, что я должен создавать новый вектор каждый раз, когда я вызываю push_back.)

Вы не создаете новый вектор. push_back возвращает лениво оцененную view в расширенной последовательности. Если вы хотите создать новый вектор, то, например, typedefNewStuff в

typedef fusion::vector<Base*, Alpha*, Bravo*, Base*, Alpha*> NewStuff; 

Ваша программа работает тогда.

Btw, fusion - очень функциональный дизайн. Я думаю, что это будет больше слияния, если бы вы хранили фактические объекты, а не указатели, и использовали transform. Логика chug затем будет выведена из классов в struct chug, которая имела бы соответствующие operator() для каждого типа. Тогда не нужно было создавать новые векторы, вы могли бы работать с лениво оцененными видами.

+0

Очень полезно, спасибо. Как можно было бы переключиться на реальные объекты, особенно если они не копируются? (Не уверен, что копии слияния). – Kyle

+0

Ну, по крайней мере, это упрощает управление памятью (нет необходимости явно удалять где-то, исключение - безопасно), и вам не нужно беспокоиться о возможных указателях NULL (если только некоторые значения не являются необязательными). –