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

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

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

Сообщений: 11445


Просмотр профиля
« : Июнь 03, 2016, 08:19 »

Добрый день

Пример: есть такой темплейт
Код
C++ (Qt)
template <class T>
int GetMaxNegative( const T & vec )
{
int maxV = 0;
for (size_t i = 0; i < vec.size(); ++i) {
int val = vec[i];
if (val >= 0) continue;
if (!maxV || val > maxV)
maxV = val;
}
 
return maxV;
}
Хорошо, теперь я могу его использовать для любых контейнеров с прямым доступом (std::vector, QVector,  QList). Но вот мне понадобилось напр так
Код
C++ (Qt)
int GetMaxNegative( const QWidgetList & vec )
{
int maxV = 0;
for (size_t i = 0; i < vec.size(); ++i) {
int val = vec[i]->x();
if (val >= 0) continue;
if (!maxV || val > maxV)
maxV = val;
}
 
return maxV;
}
Из-за разницы в обращении к эл-ту приходится переписывать. Ну или чуть более сложный случай - напр "x" в координатах заданного виджета (а не парента). Основания для обобщения вроде имеются, но как это лучше сделать?

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

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Июнь 03, 2016, 08:28 »

http://ru.cppreference.com/w/cpp/algorithm/max_element не?
Записан

ArchLinux x86_64 / Win10 64 bit
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 03, 2016, 09:18 »

Ну вот, как говорит мой свояк, "абы фатануть" Улыбающийся Только ради вычисления максимума нет смысла заморачиваться, это чисто для примера.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #3 : Июнь 03, 2016, 10:59 »

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

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июнь 03, 2016, 11:07 »

Ну пример kuzulis еще намекает на функторы. Вы можете вынести код возвращающий значение (эдакий геттер) для сравнения за шаблон. В случае с контейнером чисел, геттер будет просто возвращать число из коллекции, а в случае виджета или QPoint - значение нужной величины (в вашем случае значение x).
Не хотелось бы "эдакий", т.к. его придется обеспечивать и для всех банальных контейнеров.

Да, а где же наш энтузиаст шаблонной магии?  Улыбающийся
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #5 : Июнь 03, 2016, 11:18 »

Не хотелось бы "эдакий", т.к. его придется обеспечивать и для всех банальных контейнеров.
Вместо функтора для getter-a можно задействовать опциональную std::function.
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 03, 2016, 11:30 »

Вместо функтора для getter-a можно задействовать опциональную std::function.
А можно пример как это будет выглядеть в данном случае? (std::function пока в мой арсенал не входит, все не переползем на С++ 11)

И еще могут понадобиться доп данные для чтения/записи эл-та (см пример с "х" в координатах заданного виджета)
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #7 : Июнь 03, 2016, 11:34 »

Не хотелось бы "эдакий", т.к. его придется обеспечивать и для всех банальных контейнеров.
Лямбды это упростят:

Код
C++ (Qt)
#include <vector>
#include <iostream>
 
using namespace std;
 
template<typename Ret, typename It, typename Func>
Ret getMaxNegative( It beg, It end, Func get )
{
Ret maxV = 0;
for( It i = beg; i != end; ++i )
{
Ret val = get( *i );
if( val >= 0 )
continue;
 
if( !maxV || val > maxV )
maxV = val;
}
 
return maxV;
}
 
template<typename Ret, typename It>
Ret getMaxNegative( It beg, It end )
{
return getMaxNegative<Ret, It>( beg, end, []( Ret v ) { return v; } );
}
 
struct Point
{
int x;
int y;
};
 
int main( int, char ** )
{
cout << "Hello World!" << endl;
 
std::vector<int> v{ 3, -1, -14, 1, 5, 9 };
cout << "Result = " << getMaxNegative<int>( v.begin(), v.end() ) << endl;
 
std::vector<Point> p{ { 10, 10 }, { 20, 20 }, { -30, 30 }, { -10, 40 } };
cout << "Result = " << getMaxNegative<double>( p.begin(), p.end(), []( const Point &v ){ return v.x; } ) << endl;
 
return 0;
}
 
« Последнее редактирование: Июнь 03, 2016, 11:39 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июнь 03, 2016, 13:20 »

Лямбды это упростят:
Так-то оно так, но вот есть десяток ф-ций наподобие GetMaxNegative - и каждую придется "одевать", непрахтишно. Да и передача хвунктора как-то не очень. Нельзя ли сосредоточить весь новый код в том что "подается на вход GetMaxNegative" ?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #9 : Июнь 03, 2016, 13:22 »

Нельзя ли сосредоточить весь новый код в том что "подается на вход GetMaxNegative" ?
На вход подается коллекция QPoint, по какой оси должен искаться максимум? А если коллекция QColor?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #10 : Июнь 03, 2016, 14:40 »

Стремиться, имхо, надо к следующему:

Код
C++ (Qt)
template <class T>
int GetVectorValue(const T & vec, int index) const
{
   return vec[index];
}
 
template <class T>
int GetVectorValueByX(const T & vec, int index) const
{
   return vec[index]->x();
}
 
template <class T>
int GetVectorValueByY(const T & vec, int index) const
{
   return vec[index]->y();
}
 
// ... blabla
 
template <class T, class F = GetVectorValue>
int GetMaxNegative( const T & vec, F* fvec  )
{
int maxV = 0;
for (size_t i = 0; i < vec.size(); ++i) {
int val = fvec(vec, i);
if (val >= 0) continue;
if (!maxV || val > maxV)
maxV = val;
}
 
return maxV;
}
 

Таким образом через параметры можно передать и вектор, и функтор для доступа к нему (если базовый не подходит).
« Последнее редактирование: Июнь 03, 2016, 14:42 от Racheengel » Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4732



Просмотр профиля WWW
« Ответ #11 : Июнь 03, 2016, 15:19 »

Лямбды это упростят:
Так-то оно так, но вот есть десяток ф-ций наподобие GetMaxNegative - и каждую придется "одевать", непрахтишно. Да и передача хвунктора как-то не очень. Нельзя ли сосредоточить весь новый код в том что "подается на вход GetMaxNegative" ?
такое вообще бывает в нединамических языках? (ну кроме switch-enum подхода)
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #12 : Июнь 03, 2016, 15:46 »

Можно специализировать getter_helper под различные пользоваткльские типы и дёргать его из функции:

Код
C++ (Qt)
template <class>
struct getter_helper
{
   template <class R, class U>
   static R get(const U & x)
   {
       return x;
   }
};
 
template <>
struct getter_helper<QPoint>
{
   template <class R, class U>
   static R get(const U & p)
   {
       return p.x();
   }
};
 
template <class T>
int GetMaxNegative( const T & vec)
{
   int maxV = 0;
   for (size_t i = 0; i < vec.size(); ++i) {
       int val = getter_helper<typename T::value_type>::get(vec[i]);
       if (val >= 0) continue;
       if (!maxV || val > maxV)
           maxV = val;
   }
 
   return maxV;
}
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Июнь 03, 2016, 15:57 »

такое вообще бывает в нединамических языках? (ну кроме switch-enum подхода)
Не понял, что "бывает"? В смысле десятки ф-ций работающих с одним контейнером? Да, конечно
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Июнь 03, 2016, 16:11 »

Можно специализировать getter_helper под различные пользоваткльские типы и дёргать его из функции:
Так мне кажется логичнее, но зачем нам засорять код рабочих ф-ций каким-то getter_helper'ом ? Почему не так
Код
C++ (Qt)
struct CWxContainer {
CWxContainer( const QWdgetList & lst, QWidget * coord ) :
  mLst(lst),
  mCoord(coord)
 {
 }
 
 size_t size( void ) const { return mLst.size(); }
 int operator[] ( size_t index ) const { return mCoord->mapFromGlobal(mLst[index]->mapToGlobal(QPoint(0, 0))).x(); }
 
// data
const QWdgetList & mLst;
QWidget * mCoord;
};
Вот правда не знаю как сделать запись, чтобы [] возвращал ссылку на int (ее ведь "в оригинале" может не быть)
« Последнее редактирование: Июнь 03, 2016, 16:13 от Igors » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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