Как правильно использовать boost :: fusion :: push_back? - PullRequest
4 голосов
/ 16 мая 2010
// ... 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.)

1 Ответ

1 голос
/ 16 мая 2010

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

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

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

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

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

...