Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Сентябрь 12, 2011, 15:19



Название: template + operator[]
Отправлено: Igors от Сентябрь 12, 2011, 15:19
Добрый день

Созрел template, многовато однотипных классов. Использование (упрощенный пример)

Код
C++ (Qt)
class CUser {
...
CList * mList;
};
 
При этом фактический тип mList может быть напр std::vector <float> или std::vector <double> или другой, и это может меняться в runtime. Поэтому объявлять template в CUser мне не резон. Ладно, сделал так

Код
C++ (Qt)
struct CList {
...
};
 
template <class T>
struct CListVec : public CList, public std::vector <T> {
...
};
 
// теперь я могу написать напр
mList = new CListVec <float>;
 
Но как мне теперь заполучить операторы [], size() для класса CList ?

Спасибо



Название: Re: template + operator[]
Отправлено: kambala от Сентябрь 12, 2011, 15:46
dynamic_cast<std::vector<float> *>(mList)->size()


Название: Re: template + operator[]
Отправлено: BRE от Сентябрь 12, 2011, 15:59
2 kambala: Вроде этого должно быть достаточно.
Код
C++ (Qt)
mList->size()
(*mList)[ 1 ]
 
Не?

Но как мне теперь заполучить операторы [], size() для класса CList ?
А что там в CList?


Название: Re: template + operator[]
Отправлено: kambala от Сентябрь 12, 2011, 16:10
у нас тут не динамический язык :) вот в Objective-C подобное бы прокатило.


Название: Re: template + operator[]
Отправлено: Akon от Сентябрь 12, 2011, 16:36
У CList есть совпадающие c std::vector функции?
Код:
mList = new CListVec <float>;
int CList_size = static_cast<CList*>(mList)->size();
size_t vector_size = static_cast<std::vector<float>*>(mList)->size();


Название: Re: template + operator[]
Отправлено: SASA от Сентябрь 12, 2011, 17:36
Код
C++ (Qt)
template <class T>
struct CListVec : public CList, public std::vector <T> {
...
};
 
А зачем наследоваться от двух контейнерных классов. Или CList имеет какую-то изощрённую логику?


Название: Re: template + operator[]
Отправлено: Igors от Сентябрь 12, 2011, 17:45
Код
C++ (Qt)
mList->size()
(*mList)[ 1 ]
 
Хотелось бы, но как это сделать?  (как объявить этот оператор в CList)

У CList есть совпадающие c std::vector функции?
Код:
mList = new CListVec <float>;
int CList_size = static_cast<CList*>(mList)->size();
size_t vector_size = static_cast<std::vector<float>*>(mList)->size();
Совпадающих нет, CList делается только как обертка для CListVec. Но как избежать "декодирования", ведь фактический тип может быть разным CListVec.<T>

А зачем наследоваться от двух контейнерных классов. Или CList имеет какую-то изощрённую логику?
CList не контейнер, наследоваться от std::vector необязательно, можно сделать его членом, не суть.
Дело в том что объявлять так
Код
C++ (Qt)
template <class T>
class CUser {
...
 
std::vector <T> * mList;
};
 
мне не подходит, mList должен быть всяким-разным (для одного класса CUser)


Название: Re: template + operator[]
Отправлено: Akon от Сентябрь 12, 2011, 18:19
Код:
class User
{
...
private:
void* mList;  // pointer to vector<int>, vector<float> ...
};

template <typename T>
class TheUser : public User
{
...
public:
const std::vector<T>* mList() const { return static_cast<const std::vector<T>*>(mList); }
};

TheUser<float> floatUser;

Вообще (если с нуля), в базовом контейнере хранятся указатели на элементы (это даст полиморфизм в рантайм), а тонкая шаблонная обертка навешивается на наследников для статического приведения типов интерфейсных функций.


Название: Re: template + operator[]
Отправлено: BRE от Сентябрь 12, 2011, 18:40
Сообразил чего хочется... и как-то пока не представляю как это сделать и вообще возможно ли это сделать...
В классе CUser хочется объявить указатель на класс CList, который будет базовым для списков разных типов и в дальнейшем работать через этот указатель со списком конкретного типа, причем типы списков могут изменяться runtime.
Значит в классе CList должен быть описан весь интерфейс, через который можно работать с элементами. И если описать виртуальный метод size труда не составит, то методы для работы с элементами описать в нем будет просто не возможно - конкретного типа мы еще не знаем.


Название: Re: template + operator[]
Отправлено: Igors от Сентябрь 12, 2011, 18:58
Сообразил чего хочется... и как-то пока не представляю как это сделать и вообще возможно ли это сделать...
В классе CUser хочется объявить указатель на класс CList, который будет базовым для списков разных типов и в дальнейшем работать через этот указатель со списком конкретного типа, причем типы списков могут изменяться runtime.
Да, и ситуация не такая уж фантастическая. Есть 2 класса, у одного массив/контейнер float, у другого double, классы знают как эти массивы создавать/заполнять. И есть класс CUser, который умеет с контейнерами что-то делать (напр вычислять среднее). Конечно это условно, для float/double нет смысла городить, просто суть та же. Заметим что если бы mList не требовался как член CUser, то проблем никаких - просто функция-член принимающая template аргумент.

Значит в классе CList должен быть описан весь интерфейс, через который можно работать с элементами. И если описать виртуальный метод size труда не составит, то методы для работы с элементами описать в нем будет просто не возможно - конкретного типа мы еще не знаем.
Ну впарить в mList флажок mType и потом switch - дело нехитрое. Но хочется же цивильно..


Название: Re: template + operator[]
Отправлено: BRE от Сентябрь 12, 2011, 19:25
Ну впарить в mList флажок mType и потом switch - дело нехитрое. Но хочется же цивильно..
Не хитрое?
А как будем менять тип в методах в зависимости от значения флага?
Код
C++ (Qt)
void append( (( mType )? float : double)  item )
 


Название: Re: template + operator[]
Отправлено: BRE от Сентябрь 12, 2011, 19:47
Да, и ситуация не такая уж фантастическая.
Она может и не такая фантастическая, только по моему нормально на C++ не описываемая. Можно воспользоваться чем то типа boost::any, но лучше пересмотреть архитектуру этих классов. Есть стандартные контейнеры и есть стандартные алгоритмы, там все просто и прозрачно.


Название: Re: template + operator[]
Отправлено: Igors от Сентябрь 12, 2011, 21:33
Так, ну один вариант есть

Код
C++ (Qt)
#include <vector>
 
struct CList {
virtual size_t size ( void ) = 0;
virtual double GetDoub ( size_t index ) = 0;
};
 
template <class T>
struct CListVec : public CList {
CListVec( const T & elem ) { mVec.push_back(elem); }
 
virtual size_t size ( void ) { return mVec.size(); }
virtual double GetDoub ( size_t index ) { return mVec[index]; }
 
std::vector <T> mVec;
};
 
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
CList * vecLst1 = new CListVec <double> (0.123);
CList * vecLst2 = new CListVec <float> (0.456f);
double d1 = vecLst1->GetDoub(0);
double d2 = vecLst2->GetDoub(0);
printf("d1 = %g, d2 = %g, size = %ld\n", d1, d2, vecLst1->size());
return 0;
}
 
Виртуальщина мне не очень нравится, ну да ладно.
По поводу оператора [] я был неправ - мне наоборот, не нужно (нельзя) его иметь, потому что он возвращает ссылку. То есть если данные хранятся как float, то ссылка на double просто ошибка (даже если мне удастся ее взять). Ну со стороны CUser вполне достаточно get/set по индексу