Удаление из контейнера внешеполиморфных объектов
От: Аноним  
Дата: 24.09.09 12:24
Оценка:
Через внешний полиморфизм в контейнер помещаются объекты разных типов. Необходимо обеспечить возможность удаления из контейнера, зная исходный объект. Пока единственное, что смог придумать — использовать void *. Нет ли элегантного решения?

Упрощенный пример выглядит так:
class pure1
{
public:
    void foo1() { std::cout << "pure1::foo1()" << std::endl; }
};

class pure2
{
public:
    void foo2() { std::cout << "pure2::foo2()" << std::endl; }
};

class polymorphy
{
public:
    virtual void foo() = 0;

//    virtual bool is_equal(void *pure_) = 0;
};

template <>
void polymorphy_foo(pure1 &t)
{
    t.foo1();
}

template <>
void polymorphy_foo(pure2 &t)
{
    t.foo2();
}


template <typename T>
class polymorphy_adapter : public polymorphy
{
private:
    T * _pure;

public:
    polymorphy_adapter(T &t) : _pure(&t) {}

    virtual void foo()
    {
        polymorphy_foo<T>(*_pure);
    }

//    virtual bool is_equal(void *pure_)
//    {
//        return (_pure == pure_);
//    }

};

void test()
{
    pure1 p1;
    pure2 p2;
    typedef boost::shared_ptr<polymorphy> item_type;
    std::vector<item_type> v;
    v.push_back(item_type(new polymorphy_adapter<pure1>(p1)));
    v.push_back(item_type(new polymorphy_adapter<pure2>(p2)));

    v[0]->foo();
    v[1]->foo();
}
Re: Удаление из контейнера внешеполиморфных объектов
От: Кодт Россия  
Дата: 25.09.09 09:09
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Через внешний полиморфизм в контейнер помещаются объекты разных типов. Необходимо обеспечить возможность удаления из контейнера, зная исходный объект. Пока единственное, что смог придумать — использовать void *. Нет ли элегантного решения?


Что-то в твоём коде не видно void*.
Может быть, ты имел в виду vector< shared_ptr<void> > с очевидной проблемой — что вообще можно делать с такими указателями, кроме удаления и кастинга?

А так, в принципе, нормальное решение.
Единственный момент — это как организовывать интерфейс
— на абстрактном базовом классе и шаблонном наследнике (твой подход)
— на таблицах функций в каждом экземпляре
— — рукодельных
— — стандартных
// using namespace boost или std::tr1 - по вкусу

///////////////////////
// нам нужна только foo

// нет смысла делать шаблон со специализациями, достаточно перегрузить
function<void()> getfoo(pure1* p) { return bind(&pure1::foo1, p); }
function<void()> getfoo(pure2* p) { return bind(&pure2::foo2, p); }


pure1 v1;
pure2 v2;
pure3 v3;
vector<function<void()> doers;
doers.push_back(getfoo(&v1));
doers.push_back(getfoo(&v2));
doers.push_back(bind(&pure3::foo123, &v3, 1, 2, 3)); // можно и руками собрать
doers[2](); // v3.foo3(1,2,3);


//////////////////////////
// нам нужен букет функций

// структура с именованными полями
struct funs
{
    function<void()> foo;
    function<int(int)> bar;
    function<int(int,int)> buz;
};

funs getfuns(pure1* p)
{
    funs fs;
    fs.foo = bind(&pure1::foo1, p);
    fs.bar = bind(&pure1::bar1, p, _1);
    fs.buz = bind(&pure1::buz1, p, _1, _2);
    return fs;
}

vector<funs> doers;
doers.push_back(getfuns(&v1));
doers[0].buz(1,2); // v1.buz1(1,2)

// или кортеж
enum { FOO, BAR, BUZ };
typedef tuple< function<void()>, function<int(int)>, function<int(int,int)> > funset;
// если функций всего две, можно взять не tuple, а pair

funset getfunset(pure1* p)
{
    return make_tuple(
        bind(&pure1::foo1,p),
        bind(&pure1::bar1,p,_1),
        bind(&pure1::buz1,p,_1,_2)
        );
}

vector<funset> doers;
doers.push_back(getfunset(&v1);
doers[0].get<BAR>()(1); // v1.bar1(1)

Кстати, вместо голых указателей можно использовать и умные. Для общности.
function<void()> getfoo(shared_ptr<pure1> p) { return bind(&pure1::foo1, p); }

void nodelete(void*) {}

pure1 v1;
function<void()> f1 = getfoo(shared_ptr<pure1>(v1,nodelete)); // с этой функцией надо быть аккуратнее - она валидна, пока жив v1
function<void()> f2 = getfoo(shared_ptr<pure1>(new pure1)); // а с этой можно делать что угодно
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: Удаление из контейнера внешеполиморфных объектов
От: Аноним 955  
Дата: 25.09.09 19:24
Оценка:
Здравствуйте, Кодт, Вы писали:

А>>Через внешний полиморфизм в контейнер помещаются объекты разных типов. Необходимо обеспечить возможность удаления из контейнера, зная исходный объект. Пока единственное, что смог придумать — использовать void *. Нет ли элегантного решения?


К>Что-то в твоём коде не видно void*.


Эта часть кода закомментирована:

//    virtual bool is_equal(void *pure_) = 0;


//    virtual bool is_equal(void *pure_)
//    {
//        return (_pure == pure_);
//    }


Проблема в том, как без void * найти элемент контейнера (для последующего удаления), соответствующий, например p1.

К>А так, в принципе, нормальное решение.


А мне вот void * спать спокойно не даёт

К>Единственный момент — это как организовывать интерфейс

К>- на абстрактном базовом классе и шаблонном наследнике (твой подход)
К>- на таблицах функций в каждом экземпляре
К>- — рукодельных
К>- — стандартных

Реальные методы, которые я упростил до foo1() и foo2(), имеют в качестве аргументов итераторы, т.е. шаблонные, поэтому мой вариант предпочтительнее.
Re[3]: Удаление из контейнера внешеполиморфных объектов
От: Кодт Россия  
Дата: 26.09.09 14:15
Оценка:
Здравствуйте, Аноним 955, Вы писали:

К>>Что-то в твоём коде не видно void*.


А9>Эта часть кода закомментирована:


А9>
А9>//    virtual bool is_equal(void *pure_)
А9>//    {
А9>//        return (_pure == pure_);
А9>//    }
А9>


То есть, сравниваешь адреса, но не содержимое?
Тогда не вижу никакой проблемы. Ну разве что с множественным наследованием нужно быть аккуратным.

А9>Проблема в том, как без void * найти элемент контейнера (для последующего удаления), соответствующий, например p1.


А9>Реальные методы, которые я упростил до foo1() и foo2(), имеют в качестве аргументов итераторы, т.е. шаблонные, поэтому мой вариант предпочтительнее.


Нужно было с самого начала сказать, что у тебя мультиметод (полиморфный по двум аргументам — элементу контейнера и искомому значению).
Понятно, что во время исполнения шаблоны уже не помогут. Значит, нужно смотреть, как ту же самую задачу решать без шаблонов. Способов много — хоть двойная диспетчеризация, хоть вообще вариантные типы (boost::any). Но это уже надо на суть методов fooNNN смотреть.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.