Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Август 28, 2015, 12:09



Название: Массив темплейт классов
Отправлено: Igors от Август 28, 2015, 12:09
Добрый день

Есть простой темплейт класс
Код
C++ (Qt)
template <class T>
struct MyClass {
...
std::vector<T> mData;
};
Прочитал из файла число таких, напр это 2. Из них первый напр MyClass<int>, второй MyClass<double>,  для каждого тип в файле указан. Как мне представить считанные экземпляры в виде массива? Ну ясно все эл-ты массива должны иметь один тип, поэтому чем можно удобно его заменить?

Спасибо


Название: Re: Массив темплейт классов
Отправлено: vbv от Август 28, 2015, 13:42
Абстрактным классом.
А темплейт унаследовать от этого абстрактного класса.


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 28, 2015, 13:46
Абстрактным классом.
А темплейт унаследовать от этого абстрактного класса.
Ну да, и массив не классов а указателей на абстрактный. Так я умею, но думал, может уже как-то по-новому можно (новый стандарт и все такое)


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 28, 2015, 13:50
boost::any, variant?


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 29, 2015, 15:15
Чтобы не плодить темы - здесь же еще один простой (надеюсь)  вопрос по template
Код
C++ (Qt)
typedef MyBaseClass * (*CreateFunc)( int param1... );
 
MyBaseClass * СreateСlassFloat( int param1... ) { return new MyDerivedClass<float>(param1...); }
MyBaseClass * СreateСlassInt( int param1... ) { return new MyDerivedClass<int>(param1...); }
... и.т.д
 
Не смертельно, но хотелось бы избежать такого расписывания. У меня есть табличка/мапа "имя класса - ф-ция его создания"
Цитировать
{ "Real", СreateСlassFloat }
{ "Integer", СreateСlassInt }
Вместо которой лучше было бы
Цитировать
{ "Real", СreateСlass<float> }
{ "Integer", СreateСlass<int> }
Как это оформить?

Спасибо


Название: Re: Массив темплейт классов
Отправлено: Old от Август 29, 2015, 16:02
Код
C++ (Qt)
template<typename T>
MyBaseClass *createClass( int param1... )
{
   return new MyDerivdClass<T>( param1... );
}
 


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 29, 2015, 16:15
Код
C++ (Qt)
template<typename T>
MyBaseClass *createClass( int param1... )
{
   return new MyDerivdClass<T>( param1... );
}
 

Если я правильно понял, то он (igors) не может таким образом запихнуть в мап указатель на шаблон функции)
В смысле, как я понял, есть такой мап:
Код
C++ (Qt)
std::map<std::string, CreateFunc>
 
Вообщем, зная TC надо подождать) Может внезапно какие новые детали всплывут)   
   


Название: Re: Массив темплейт классов
Отправлено: Old от Август 29, 2015, 16:20
А, ну тогда еще std::function в придачу. :)


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 30, 2015, 07:05
Если я правильно понял, то он (igors) не может таким образом запихнуть в мап указатель на шаблон функции)
В смысле, как я понял, есть такой мап:
Код
C++ (Qt)
std::map<std::string, CreateFunc>
 
Вообщем, зная TC надо подождать) Может внезапно какие новые детали всплывут)   
Ну так и есть - как я в мапе/табличке "идентифицирую" напр CreateFunc<float> ?


Название: Re: Массив темплейт классов
Отправлено: Old от Август 30, 2015, 07:08
Что значит как идентифицирую?
Вы по ключу получите функцию, которая при вызове создаст вам объект.


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 30, 2015, 12:51
Какое-то станное решение с мапом и указателями на эти функции.. Может я опять не всё понимаю, но не проще ли было бы тогда завести обычный список std::list<std::string> и + один указатель на функтор:

Код
C++ (Qt)
 
struct creator
{
   template<class T>
   MyBaseClass * operator()( int param1... ) const
   {
        return new MyDerivdClass<T>( param1... );
   }
};
 
std::list<std::string> type_list;
 
 

И всё..

Я, правда, не знаю как это всё у вас используется и т.п. и т.д.. но..


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 30, 2015, 14:11
Используется очень просто. Вот мапа
Цитировать
{ "Real", СreateСlassFloat }
{ "Integer", СreateСlassInt }
Считали строку из файла, напр она "Real" - ну значит вызвали СreateСlassFloat и сохранили возвращенное значение. Неаккуратно что СreateСlassFloat, СreateСlassInt и др - вызовы отличающиеся лишь типом темплейта


Название: Re: Массив темплейт классов
Отправлено: Old от Август 30, 2015, 15:06
Одним словом это называется фабрика.
Теперь сможете сделать аккуратней.


Название: Re: Массив темплейт классов
Отправлено: _Bers от Август 30, 2015, 15:09
Используется очень просто. Вот мапа
Цитировать
{ "Real", СreateСlassFloat }
{ "Integer", СreateСlassInt }
Считали строку из файла, напр она "Real" - ну значит вызвали СreateСlassFloat и сохранили возвращенное значение. Неаккуратно что СreateСlassFloat, СreateСlassInt и др - вызовы отличающиеся лишь типом темплейта

нужно что-то типа такого?

http://rextester.com/JFRPI86597

Код:
//Title of this code
//g++  4.9.2

#include <functional>
#include <iostream>
#include <string>
#include <map>

struct IObject
{
    virtual ~IObject(){}
   
    virtual void View()const = 0;
};

template<class T>
struct Object : IObject
{
    void View()const { std::cout<<typeid(*this).name()<<std::endl; }
};


template<class T>
IObject* CreateObject()
{
    return new Object<T>;
}


int main()
{
    std::cout << "Hello, world!\n";
   
    typedef std::function< IObject*() >
        CreateFunc;
   
    typedef std::map<std::string, CreateFunc>
        Bind;
   
    Bind factory;
   
    factory["real"]    = CreateObject<float>;
    factory["integer"] = CreateObject<int>;
   
    auto* obj = factory["integer"]();
    obj->View();
   
    factory["real"]()->View();
   
}


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 30, 2015, 15:19
Ну тогда так:

Код
C++ (Qt)
class creator_base
{
public:
   virtual ~creator_base() {}
   virtual MyBaseClass * operator()( int param1... ) const = 0;
};
 
template <class T>
class creator : public creator_base
{
public:
   virtual MyBaseClass* operator()(int param1...) const { return new MyDerivdClass<T>( param1... ); }
};
 
template <class T>
std::shared_ptr<creator<T>> create_function()
{
   return std::make_shared<creator<T>>();
}
 
std::map<std::string, std::shared_ptr<creator_base>> map;
 
map["Real"] = create_function<float>();
map["Integer"] =create_function<int>();
 
 


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 30, 2015, 16:38
Цитировать
Ну тогда так:

В принципе, это то же самое, что и _Bers предложил чуть выше)


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 31, 2015, 09:31
А что это значит? (как это осмыслить). Указатель на тип + скобки, а где же имя ф-ции ???
Ага, это сынтаксыс std::functon (тип возврата и в скобках аргументы). Но каким волшебным образом она понимает template ???


Название: Re: Массив темплейт классов
Отправлено: Old от Август 31, 2015, 10:02
Можно почитать про std::function самому, как уже предлагалось, или дождаться _Bers,  чтобы он все подробно разжевал. :)


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 31, 2015, 12:06
А что это значит? (как это осмыслить). Указатель на тип + скобки, а где же имя ф-ции ???
Ага, это сынтаксыс std::functon (тип возврата и в скобках аргументы). Но каким волшебным образом она понимает template ???

Да, и std::function создает "за кадром" какие-то шаред (как у m_ax) или нет?


Название: Re: Массив темплейт классов
Отправлено: Igors от Август 31, 2015, 12:22
А вот еще с темплейтами. Иногда делают так
Код
C++ (Qt)
struct CVarStruct {
int mID;   // "нормальный" член, он всегда есть
//.. еще какие-то нормальные
сhar mData[1];   // массив переменной длины
};
Ну и дальше юзают mData имея ввиду его реальную длину. Оно конечно со всех сторон плохо (липовый sizeof, new не работает и.т.д), но для тупых данных и при большом числе таких "эл-тов" память экономится хорошо - и это может окупить все минусы. Недавно думал задействовать такую городушку (правда потом отказался). Как же такой "эл-т" поместить в контейнер? Казалось бы все просто
Код
C++ (Qt)
template <size_t num>
struct Civilized {
int mID;  
сhar mData[num];  
};
Но это ничего не дает т.к. num должен быть известен на момент компиляции. Конечно можно "на базе std::vector <char>" - но там совсем кисло  :'(  Какие еще есть ходики?

Спасибо


Название: Re: Массив темплейт классов
Отправлено: m_ax от Август 31, 2015, 12:35
Цитировать
Ага, это сынтаксыс std::functon (тип возврата и в скобках аргументы). Но каким волшебным образом она понимает template  ???
Это, фактически, специализация шаблона:
Код
C++ (Qt)
template <class>
struct object;
 
template <class T, class U>
struct object<T (U)> {};
 

Цитировать
Да, и std::function создает "за кадром" какие-то шаред (как у m_ax) или нет?
Нет, это просто функтор, который хранит указатель на функцию, или на член-функцию и вызывает её в operator(), от вида которого Вам так плохеет  :)
 


Название: Re: Массив темплейт классов
Отправлено: _Bers от Август 31, 2015, 20:27
Можно почитать про std::function самому, как уже предлагалось, или дождаться _Bers,  чтобы он все подробно разжевал. :)

мне влом.

оно это умеет, и достаточно.

технические подробности - чрезвычайно (просты?) сложны для понимания.
производители компиляторов (стандартной библиотеки) юзают расширения компиляторов.
так что там под капотом "чистым с++" не пахнет.


могу лишь сказать, что по перфомансу,
std::function медленный по времени создания,
но имеет порядка 10 микросекунд выигрыша за каждый аргумент при запуске.

и этот отрыв мне средствами самого с++ (по честному) преодолеть не удалось.


Название: Re: Массив темплейт классов
Отправлено: m_ax от Сентябрь 01, 2015, 00:34
Цитировать
могу лишь сказать, что по перфомансу,
std::function медленный по времени создания,
но имеет порядка 10 микросекунд выигрыша за каждый аргумент при запуске.
10 микросекунд (10^-6)..? А какова была погрешность самих измерений?)   


Название: Re: Массив темплейт классов
Отправлено: Igors от Сентябрь 01, 2015, 10:21
технические подробности - чрезвычайно (просты?) сложны для понимания.
производители компиляторов (стандартной библиотеки) юзают расширения компиляторов.
так что там под капотом "чистым с++" не пахнет.
Ну хорошо, кое-что надо "тупенько запомнить", все понимать - головы не хватит. А может ли такая ф-ция иметь др модель вызова (не cdecl)?


Название: Re: Массив темплейт классов
Отправлено: Old от Сентябрь 01, 2015, 10:26
А может ли такая ф-ция иметь др модель вызова (не cdecl)?
Что вы имеете ввиду под другой моделью вызова?


Название: Re: Массив темплейт классов
Отправлено: Igors от Сентябрь 02, 2015, 07:26
Еще проблемка (уже не первый раз с ней сталкиваюсь). Ладно, объявил базовый класс
Код
C++ (Qt)
struct MyBaseClass {
virtual void Apply( size_t index ) = 0;
virtual size_t Size( void  ) const = 0;
 
template <class T>
T Get( size_t index );  // ???
};
И унаследовался с темплейтом
Код
C++ (Qt)
template <class T>
struct MyDerivedClass : public MyBaseClass {
void Apply( size_t index );
size_t Size( void  ) const { return mData.size(); }
 
// data
std::vector <T> mData;
};
Теперь я могу иметь контейнер указателей на базовый класс. C реализацией методов Size и Apply проблем не возникает, но что делать с Get()? Он ведь не может быть виртуалом. А необходимость в нем (или даже в операторах []) возникает часто, напр
Код
C++ (Qt)
template <class T>
T CalcAverage( const MyBaseClass & src )
{
T sum = 0;
for (size_t i = 0; i < src.Size(); ++i)
 sum += src.Get<T>(i);
...
}
Если бы аргументом был MyDerivedClass<T> - все хорошо, но где ж такой аргумент взять?


Название: Re: Массив темплейт классов
Отправлено: Tuxford от Сентябрь 02, 2015, 11:14
Так дело имеем с темплейтной функцией. Вот она не может быть виртуальной.
Но можно сделать класс темплейнтным. Тогда Get может быть виртуальной.

Код
C++ (Qt)
template <class T>
struct MyBaseClass {
virtual void Apply( size_t index ) = 0;
virtual size_t Size( void  ) const = 0;
virtual T Get( size_t index ) = 0;  
};

Код
C++ (Qt)
template <class T>
struct MyDerivedClass : public MyBaseClass {
void Apply( size_t index );
size_t Size( void  ) const { return mData.size(); }
T Get(size_t index) { return mData[index]; }
// data
std::vector <T> mData;
};
 

Код
C++ (Qt)
template <class T>
T CalcAverage( const MyBaseClass<T> & src )
{
T sum = 0;
for (size_t i = 0; i < src.Size(); ++i)
 sum += src.Get(i);
...
}
 

Такой вариант вполне будет.


Название: Re: Массив темплейт классов
Отправлено: Igors от Сентябрь 02, 2015, 11:33
Но можно сделать класс темплейнтным. Тогда Get может быть виртуальной.
Тогда мне не раскрутиться с массивом. Напр сейчас
Код
C++ (Qt)
std::vector <MyBaseClass *> channels;
...
for (size_t i = 0; i < channels.size(); ++i)
 channels[i]->Apply(...);
 
При этом наследники MyBaseClass могут иметь разные типы. А так
Код
C++ (Qt)
std::vector <MyBaseClass <А здесь что??>*> channels;


Название: Re: Массив темплейт классов
Отправлено: m_ax от Сентябрь 02, 2015, 11:35
Цитировать
Еще проблемка (уже не первый раз с ней сталкиваюсь). Ладно, объявил базовый класс
Не первый раз уже повторяю: boost::any, variant:
Код
C++ (Qt)
struct MyBaseClass {
virtual void Apply( size_t index ) = 0;
virtual size_t Size( void  ) const = 0;
 
virtual boost::any Get( size_t index ) const  = 0;
};
 


Цитировать
Но можно сделать класс темплейнтным. Тогда Get может быть виртуальной.
Так его (базовый класс) специально сделали не шаблонным)  :)




Название: Re: Массив темплейт классов
Отправлено: Igors от Сентябрь 02, 2015, 14:54
Не первый раз уже повторяю: boost::any, variant:
Хмм... заманчиво. Но все-таки сначала хочу убедиться что чисто средствами языка это слишком хлопотно. Подождем что скажет академик  :)


Название: Re: Массив темплейт классов
Отправлено: m_ax от Сентябрь 02, 2015, 18:17
Цитировать
Но все-таки сначала хочу убедиться что чисто средствами языка это слишком хлопотно.
В смысле? А в boost'е какими средствами это реализовано?) Да и недавно товарищ navrovsky писал здесь свой any)