views:

133

answers:

1
// ... 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;
};

How do I get for_each(newStuff, chug()) to work?

(Note: I'm only assuming from the overly brief documentation on boost::fusion that I am supposed to create a new vector every time I call push_back.)

+1  A: 

(Note: I'm only assuming from the overly brief documentation on boost::fusion that I am supposed to create a new vector every time I call push_back.)

You're not creating a new vector. push_back returns a lazily evaluated view on the extended sequence. If you want to create a new vector, then e.g. typedef NewStuff as

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

Your program works then.

Btw, fusion is a very functional design. I think it would be more fusion-like if you'd store actual objects rather than pointers and used transform. The chug logic would then be moved out of the classes into the struct chug which had appropriate operator()'s for each type. No new vectors would have to be created then, you could work with lazily evaluated views.

Rüdiger Hanke
Very helpful, thank you. How would switching to actual objects be beneficial, especially if they're non-copyable? (Not sure if fusion copies).
Kyle
Well at the very least, it simplifies memory management (no need to delete explicitly somewhere, exception safe) and you don't have to worry about possible NULL pointers (unless some values are meant to be optional).
Rüdiger Hanke