Russian Qt Forum
Сентябрь 30, 2024, 16:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Массив std::set  (Прочитано 9940 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Сентябрь 13, 2012, 15:32 »

Добрый день

Нужен массив std::set (ну или порожденных классов, указателей) каждый из которых хранит указатели на один и тот же класс, но использует свой функтор. Пример

Код
C++ (Qt)
std::set <MyClass *, MyFunctor1> theSet1;
..
std::set <MyClass *, MyFunctor2> theSet2;
..
std::set <MyClass *, MyFunctor3> theSet3;
 
Так нет проблем но приходится перебирать theSetxx. А хотелось бы так
Код
C++ (Qt)
for (int i = 0; i < 3; ++i) {
MyClass * data = theSet[i].find(val);
if (data)...
 

Спасибо
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Сентябрь 14, 2012, 00:09 »

Код:
    set<int> s = *(set<int> *)array[i];
Так Вы копируете все данные set, наверное Вы имели ввиду
Код
C++ (Qt)
   set<int> * s = (set<int> *)array[i];
 
Но так и компилиться не должно если set <int> нигде не объявлен и значит не "инстанциирован". А если объявить и как-то заткнуть рот компилятору, то все равно неясно как же он найдет нужный функтор, ведь метод find не виртуальный.

Записан
VPS
Гость
« Ответ #2 : Сентябрь 14, 2012, 07:39 »

Код
C++ (Qt)
set<int> * s = (set<int> *)array[i];
 
Но так и компилиться не должно если set <int> нигде не объявлен и значит не "инстанциирован". А если объявить и как-то заткнуть рот компилятору, то все равно неясно как же он найдет нужный функтор, ведь метод find не виртуальный.

Компилятор не ругается Непонимающий, но и пример мой на самом деле не корректен...
Так как в нем постоянно определяется указатель на множество вида: set<int, less<int> >. Поэтому то и поиск во втором контейнере и не проходит...
Записан
V1KT0P
Гость
« Ответ #3 : Сентябрь 14, 2012, 08:10 »

Нужен массив std::set (ну или порожденных классов, указателей) каждый из которых хранит указатели на один и тот же класс, но использует свой функтор.
Правильно ли я тебя понял: у тебя три отдельных массива из-за того что используются три разных своих функтора, а ты хочешь эти три отдельных массива запихнуть в один массив?
Тогда почему ты не можешь сделать базовый функтор, от которого будут наследоваться остальные функторы. А в массиве будешь хранить только указатель на базовый. Даже если ты используешь не свои функторы и нет возможности их менять, то можно написать свой функтор обертку. В эту обертку заворачивать функторы. При чем если сделать на шаблонах, то вообще любой функтор можно будет завернуть.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Сентябрь 14, 2012, 12:54 »

Правильно ли я тебя понял: у тебя три отдельных массива из-за того что используются три разных своих функтора, а ты хочешь эти три отдельных массива запихнуть в один массив?
У меня не 3 отдельных массива, а 3 (реально больше) std::set. Все они работают с типом MyClass * (первый template аргумент) но отличаются функторами (второй template аргумент), т.е. все они имеют разный тип. 

Тогда почему ты не можешь сделать базовый функтор, от которого будут наследоваться остальные функторы. А в массиве будешь хранить только указатель на базовый.
А как я могу "хранить функтор"? Прошу исполнить
Записан
V1KT0P
Гость
« Ответ #5 : Сентябрь 14, 2012, 21:00 »

У меня не 3 отдельных массива, а 3 (реально больше) std::set. Все они работают с типом MyClass * (первый template аргумент) но отличаются функторами (второй template аргумент), т.е. все они имеют разный тип. 
А как я могу "хранить функтор"? Прошу исполнить
Вот сразу два варианта:
1) Путем наследования от интерфейса, это если можно править классы функторов.
2) Путем шаблонного наследования от интерфеса, это если нельзя править классы функторов.
Код
C++ (Qt)
#include <iostream>
#include <vector>
 
using namespace std;
 
class MyFunctor1
{
public:
   void operator() ()
   {
       cout << "Call functor MyFunctor1" << endl;
   }
};
 
class MyFunctor2
{
public:
   void operator() ()
   {
       cout << "Call functor MyFunctor2" << endl;
   }
};
 
class MyFunctor3
{
public:
   void operator() ()
   {
       cout << "Call functor MyFunctor3" << endl;
   }
};
 
class IMultiFunctor
{
public:
   virtual ~IMultiFunctor(){}
   void operator() ()
   {
       callback();
   }
protected:
   virtual void callback() = 0;
};
 
class MyMultiFunctor1: public IMultiFunctor
{
private:
   void callback()
   {
       cout << "Call functor MyMultiFunctor1" << endl;
   }
};
 
class MyMultiFunctor2: public IMultiFunctor
{
private:
   void callback()
   {
       cout << "Call functor MyMultiFunctor2" << endl;
   }
};
 
class MyMultiFunctor3: public IMultiFunctor
{
private:
   void callback()
   {
       cout << "Call functor MyMultiFunctor3" << endl;
   }
};
 
class ITemplateFunctor
{
public:
   virtual ~ITemplateFunctor(){}
   void operator() ()
   {
       callback();
   }
protected:
   virtual void callback() = 0;
};
 
template <class T>
class MyTemplateFunctor: public ITemplateFunctor
{
public:
   MyTemplateFunctor(T *functor): m_functor( functor ){}
 
private:
   T *m_functor;
   void callback()
   {
       (*m_functor)();
   }
};
 
int main()
{
   std::vector<IMultiFunctor*> listOfInterfaceFunctor;
   std::vector<ITemplateFunctor*> listOfTemplateFunctor;
 
   IMultiFunctor* newMultiFunctor;
 
   newMultiFunctor = new MyMultiFunctor1;
   listOfInterfaceFunctor.push_back( newMultiFunctor );
   newMultiFunctor = new MyMultiFunctor2;
   listOfInterfaceFunctor.push_back( newMultiFunctor );
   newMultiFunctor = new MyMultiFunctor3;
   listOfInterfaceFunctor.push_back( newMultiFunctor );
 
   ITemplateFunctor *newTemplateFunctor;
 
   newTemplateFunctor = new MyTemplateFunctor<MyFunctor1>( new MyFunctor1 );
   listOfTemplateFunctor.push_back( newTemplateFunctor );
   newTemplateFunctor = new MyTemplateFunctor<MyFunctor2>( new MyFunctor2 );
   listOfTemplateFunctor.push_back( newTemplateFunctor );
   newTemplateFunctor = new MyTemplateFunctor<MyFunctor3>( new MyFunctor3 );
   listOfTemplateFunctor.push_back( newTemplateFunctor );
 
   for( size_t i = 0; i < listOfInterfaceFunctor.size(); ++i ){
       (*listOfInterfaceFunctor[i])();
   }
 
   for( size_t i = 0; i < listOfTemplateFunctor.size(); ++i ){
       (*listOfTemplateFunctor[i])();
   }
 
   for( size_t i = 0; i < listOfInterfaceFunctor.size(); ++i ){
       delete listOfInterfaceFunctor[i];
   }
   listOfInterfaceFunctor.clear();
 
   for( size_t i = 0; i < listOfTemplateFunctor.size(); ++i ){
       delete listOfTemplateFunctor[i];
   }
   listOfTemplateFunctor.clear();
   cin.get();
   return 0;
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Сентябрь 14, 2012, 21:32 »

Вот сразу два варианта:
1) Путем наследования от интерфейса, это если можно править классы функторов.
2) Путем шаблонного наследования от интерфеса, это если нельзя править классы функторов.
Все функторы в моих руках и, как обычно, они очень просты. Приведенный Вами код понятен - да, можно сделать функторам общую базу, а можно и обернуть. Указатели на созданные экземпляры классов поместить в контейнер - нема квешнзов. Ну а std::set то где? Напомню что он определяется как
Код
C++ (Qt)
std::set <MyClass *, MyFunctor> theSet;
 
Где MyFunctor - тип (а не экземпляр)
Записан
V1KT0P
Гость
« Ответ #7 : Сентябрь 14, 2012, 22:07 »

Код:
[quote author=Igors link=topic=23034.msg162748#msg162748 date=1347647552]
std::set <MyClass *, MyFunctor> theSet;
Где MyFunctor - тип (а не экземпляр)
[/quote]
Не использовал set, теперь понял что не про то подумал. Пока что в голову пришло только сделать для set-а шаблонный интерфейс, в который вынести нужные функции которые наследуемые классы переопределят и который будет знать только о типе хранимого объекта. А уже наследованные будут знать класс который сравнивает. Тогда просто объявишь три set-а, приведешь их к интерфейсу и запихнешь в один массив.
Записан
VPS
Гость
« Ответ #8 : Сентябрь 14, 2012, 23:27 »

Нашёл интересную статью "Неявное приведение между родственными шаблонами С++"
И на базе её попробовал сделать пример, правда поиск производится методом algorithm::find и слишком много приведений к базовому типу... Но видимо без этого не обойтись, так как в общем контейнере надо хранить объекты разных типов, преобразованных к базовому.

П.С.: если использовать метод find шаблонного класса set, то ничего не находит...
« Последнее редактирование: Сентябрь 15, 2012, 19:28 от VPS » Записан
VPS
Гость
« Ответ #9 : Сентябрь 17, 2012, 21:31 »

Немного изменил предыдущий пример. Теперь поиск set::find() работает.
Исходник, здесь.
Записан
V1KT0P
Гость
« Ответ #10 : Сентябрь 17, 2012, 22:01 »

Немного изменил предыдущий пример. Теперь поиск set::find() работает.
Исходник, здесь.
А теперь добавь в класс Less или Greater вот такую банальную строчку:
Код
C++ (Qt)
int x;
И получи чудеса.
Записан
VPS
Гость
« Ответ #11 : Сентябрь 18, 2012, 07:22 »

Немного изменил предыдущий пример. Теперь поиск set::find() работает.
Исходник, здесь.
А теперь добавь в класс Less или Greater вот такую банальную строчку:
Код
C++ (Qt)
int x;
И получи чудеса.

Получил... Непонимающий
Направьте меня на тему, что про это почитать (если правильно понял, то что-то не так с преобразованием к нужному типу).
Записан
V1KT0P
Гость
« Ответ #12 : Сентябрь 18, 2012, 08:42 »

Получил... Непонимающий
Направьте меня на тему, что про это почитать (если правильно понял, то что-то не так с преобразованием к нужному типу).
Чего там читать, добавили одну переменную и адреса всех остальных сдвинулись. Добавим новую функцию и адреса остальных функций сдвинутся. В результате сперва адреса функций и переменных совпадали и можно было C style cast-ом(Именно это ты и делал, только замаскировал статик кастом а так получил тот-же C style cast) безнаказанно. В реальном же приложении если делают новый класс, то он чем-то отличается. Вот и получается что чуть сдвинулись переменные и все начало неправильно работать. Поэтому в C++ специально сделали безопасный статик_каст, а за C style cast надо по рукам бить. Сколько я уже наслышался проблем из-за него.
Записан
VPS
Гость
« Ответ #13 : Сентябрь 18, 2012, 08:49 »

Чего там читать, добавили одну переменную и адреса всех остальных сдвинулись. Добавим новую функцию и адреса остальных функций сдвинутся. В результате сперва адреса функций и переменных совпадали и можно было C style cast-ом(Именно это ты и делал, только замаскировал статик кастом а так получил тот-же C style cast) безнаказанно. В реальном же приложении если делают новый класс, то он чем-то отличается. Вот и получается что чуть сдвинулись переменные и все начало неправильно работать. Поэтому в C++ специально сделали безопасный статик_каст, а за C style cast надо по рукам бить. Сколько я уже наслышался проблем из-за него.
Спасибо за разъяснение!
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Сентябрь 18, 2012, 12:36 »

Чего там читать, добавили одну переменную и адреса всех остальных сдвинулись. Добавим новую функцию и адреса остальных функций сдвинутся.
Думаю что можно добавить сколько угодно ф-ций (виртуальных или нет) и ничего не сдвинется.  А вариант вполне рабочий, спасибо, VPS . На мой взгляд маскировать приведение ни к чему, проще сделать один static_cast на вставке в вектор. И провериться в конструкторе функтора, напр
Код
C++ (Qt)
template<class T>
class Greater : public BaseF<T>
{
 Greater( void )
 {
  assert(sizeof(*this) == sizeof(BaseF<T>));
 }
 ...
};
 
Пробовал разобраться почему "сдвигается"
Код:
        struct _Rb_tree_impl : public _Node_allocator
        {
 _Key_compare _M_key_compare;
 _Rb_tree_node_base _M_header;
 size_type _M_node_count; // Keeps track of size of tree.
Так понял что _Key_compare - это тот самый функтор, поэтому если он имеет др размер  Плачущий
Ну в принципе обеспечить функторы одного размера - не проблема.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.274 секунд. Запросов: 23.