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

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

Страниц: 1 ... 3 4 [5] 6   Вниз
  Печать  
Автор Тема: Шаблоны.  (Прочитано 36433 раз)
BRE
Гость
« Ответ #60 : Март 27, 2012, 08:44 »

Клиент может прекрасно жить не зная ненужных (ему) подробностей, напр (упрощенно)
Код
C++ (Qt)
if (model.mSpaceUV) {
mSpaceUV->SetPoinr3F(0, (mSpaceUV->GetPoint3F(0) + mSpaceUV->GetPoint3F(1)) * 0.5);
}
 
А почему ты здесь используешь Set/GetPoint3F, а не Set/GetPoint3D или Set/GetPoint2F. Ты как здесь определил, что в чудо-контейнере точки как раз 3F? Надеешься?

Клиенту в принципе-то нужно немного: Get/Set, и др стандартные операции с контейнером. Да, будут какие-то расходы на возврат по значению, на возможный перевод float <-> double, но они вполне приемлемы
Хорошо так "упрощать". То, сё и др. А на выходе получаем дублирование чуть ли не каждого метода для каждого возможного типа и сложная расширяемость такого контейнера. Для нового типа точки придется добавить свои методы в контейнер, и самое страшное добавить поддержку в клиенты этого класса.
А то что твои решения для тебя всегда приемлемы это я знаю. Улыбающийся

Вообще объясните мне пожалуйста - ну откуда такой "полный минор"? Да, мы видим что ни один стандартный паттерн здесь не годится (насколько я знаю). Так что, обосраться и не жить, что ли? Есть довольно очевидное решение с базовым виртуальным классом (которое я и реализовал). Почему это "костыль", "велосипед", "вилы/грабли", тем более "против логики языка"? Только потому что так не писал Александреску (или кто-то еще)? Что же такого плохого мы делаем? Используем виртуальный механизм? Наследуемся template классом от non-template? И что с того, чем оно плохо?
Недостатки такого решения не в том, что есть виртуальный базовый класс, а в том что для каждого типа точек нужна отдельная поддержка в коде, причем как на стороне самого контейнера, так и на стороне его клиента. Чем же это решение отличается от variant? Результат тот-же, только более ограниченный.

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

Сообщений: 11445


Просмотр профиля
« Ответ #61 : Март 27, 2012, 09:59 »

А почему ты здесь используешь Set/GetPoint3F, а не Set/GetPoint3D или Set/GetPoint2F. Ты как здесь определил, что в чудо-контейнере точки как раз 3F? Надеешься?
Никак не определял. Клиент не обязан подстраиваться под формат хранения (хотя и такая возможность есть). Он может попросить данные в нужном ему формате, сработает соотв конструктор или оператор =. 

Хорошо так "упрощать". То, сё и др. А на выходе получаем дублирование чуть ли не каждого метода для каждого возможного типа и сложная расширяемость такого контейнера. Для нового типа точки придется добавить свои методы в контейнер, и самое страшное добавить поддержку в клиенты этого класса.
А то что твои решения для тебя всегда приемлемы это я знаю. Улыбающийся
Как и Ваши решения приемлемы для Вас Улыбающийся Появился новый тип базовых - придется добавить еще Get/Set и операторы для переливания - это все. Но базовых типов немного, это не проблема. Много получается комбинаций

Недостатки такого решения не в том, что есть виртуальный базовый класс, а в том что для каждого типа точек нужна отдельная поддержка в коде, причем как на стороне самого контейнера, так и на стороне его клиента. Чем же это решение отличается от variant? Результат тот-же, только более ограниченный.
Ну вот не надо прикидываться непонимающим. В случае варианта мы меняем формат самого элемента, в нашем случае мы оперируем с доступом к элементам хранящимся в фиксированном формате. Это разница принципиальная. Никакого "чуда" (типа контейнер хранящий все на свете) не планировалось. Речь шла об узком круге базовых структур, никто не собирался хранить напр строки. Беда теоретиков в том что они пропускают специфику мимо ушей, а потом начинают доказывать что, мол, в общем виде это недостижимо. Так в общем никто и не просил.

Вот из-за этого все проблемы. Сначала ты (ни любящий ничего) создаешь свое "решение", а потом надеешься на чудесное решение от кого-то в одну строчку, что бы особо ничего не пришлось переделывать и сразу стало зашибись.
Почему Вы думаете что каждый кто поднимает тему - жадный нуб который хочет от Вас что-то получить? Улыбающийся Я решал эту задачу так, интересно как бы делали другие, нормально. По поводу теории - я так вижу что не люблю я ее совершенно правильно. Если бы m_ax думал сам - он бы придумал в 100 раз лучше чем я. Но он оказался под влиянием глупых книг, зажался, скатился на шаблонные/банальные решения. Ото меньше надо читать всяких Скуперфильдов
Записан
BRE
Гость
« Ответ #62 : Март 27, 2012, 10:26 »

Никак не определял. Клиент не обязан подстраиваться под формат хранения (хотя и такая возможность есть). Он может попросить данные в нужном ему формате, сработает соотв конструктор или оператор =. 
В контейнере лежит точка 2F, клиент запрашивает 3D - он что получит. Кто это должен отслеживать? Компилятор уже не может, ты ему ручки отбил.
Это решение ничем не отличается от варианта и дело вовсе не в том меняем или не меняем мы тип элемента, а в том, что клиент понятия не имеет до реального вызова, что храниться в контейнере и может ли он работать с этим типом точек.

Как и Ваши решения приемлемы для Вас Улыбающийся Появился новый тип базовых - придется добавить еще Get/Set и операторы для переливания - это все. Но базовых типов немного, это не проблема. Много получается комбинаций
Могут быть клиенты, которые определяют тип точки и пытаются подстроиться под него, Тогда появиться необходимость менять еще их. А если использовать такой контейнер повсеместно, то может оказаться, что править придется очень много.

Если бы m_ax думал сам - он бы придумал в 100 раз лучше чем я. Но он оказался под влиянием глупых книг, зажался, скатился на шаблонные/банальные решения. Ото меньше надо читать всяких Скуперфильдов
Это случиться не раньше, чем m_ax отбросит глупые условия постановки задачи, которые только ты считаешь приемлемыми.
А книги зло, да.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #63 : Март 27, 2012, 11:10 »

В контейнере лежит точка 2F, клиент запрашивает 3D - он что получит. Кто это должен отслеживать? Компилятор уже не может, ты ему ручки отбил.
Пример: хранимая точка 2F (0.25f. 1.0f). Возвращаемая точка 3D (0.25, 1.0, 0.0)
Это решение ничем не отличается от варианта и дело вовсе не в том меняем или не меняем мы тип элемента, а в том, что клиент понятия не имеет до реального вызова, что храниться в контейнере и может ли он работать с этим типом точек.
Снова Вы рассматриваете "слишком общий" случай. Как правило клиенту пофиг есть ли 3-я UV координата. Типичная задача - интерполировать UV. Ну клиент будет работать с 3-мя (возможно в double), данные - считываться и сохраняться напр как 2 float. Все нормально, др случаи см ниже

Могут быть клиенты, которые определяют тип точки и пытаются подстроиться под него, Тогда появиться необходимость менять еще их. А если использовать такой контейнер повсеместно, то может оказаться, что править придется очень много.
Да, такой вариант возможен. Напр клиент хочет развернуться с SSL и его все-таки не устраивает конвертация (пусть относительно дешевая). В конце-концов Append - это тоже пример когда нужен "конкретный тип" (а не общий механизм). В этом случае я (пока) не вижу др решений кроме (уродливого) switch. Предлагайте - обсудим. А просто так охаять чужую корову - ума не надо  Улыбающийся

Это случиться не раньше, чем m_ax отбросит глупые условия постановки задачи, которые только ты считаешь приемлемыми.
А книги зло, да.
Ну понеслась.. "Это неправильные пчелы! Они дают неправильный мед!". Но где ж я возьму "правильных" (чтобы было точно по книжке)?  Улыбающийся Конечно я не имею права грузить Вас спецификой, но я никак не выдрючивался, не усложнял задачу, наоборот - максимально упростил как смог. Вы легко можете это проверить слегка погуглив.

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

Сообщений: 2095



Просмотр профиля
« Ответ #64 : Март 27, 2012, 11:12 »

Согласен с BRE)

Вариант (variant) здесь будет более гибким как раз из-за того, что не нужно будет переопределять функции set/get для каждого типа точек. И вообще (с вариантом) само наследование отпадает.
Но не подходит, ладно..

Остаётся вариант с наследованием и последующим переопределением гетеров, сетеров.
Я же предлагал такой вариант (где в базовом класе будут только две шаблонные функции не виртуальные)
Код
C++ (Qt)
struct base
{
   viryual ~base() {}
   template <class Derived, class Point>
   void set(size_t index, const Point &p) {
       Derived *d = dynamic_cast<Derived*>(this);
       if (d)
           d->vector[index] = p;
   }
   template <class Derived, class Point>
   Point get(size_t index) const {
       Derived *d = dynamic_cast<Derived*>(this);
       if (d)
          return d->vector[index];
       return Point();
   }
};
 

Чем этот вариант хуже того, где в базовый класс вводятся виртуальные функции для каждого типа точки?
 
Записан

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #65 : Март 27, 2012, 11:28 »

Согласен с BRE)
Плачущий
Чем этот вариант хуже того, где в базовый класс вводятся виртуальные функции для каждого типа точки?
А как Вы позовете такие get/set? Откуда клиент возьмет Derived:?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #66 : Март 27, 2012, 11:39 »

Цитировать
А как Вы позовете такие get/set? Откуда клиент возьмет Derived:?
Да, это верно) Он же (клиент) его не знает..

Ну тогда, следственно, все Ваши условия диктуют принять вариант с наследованием. А как ещё? 
Записан

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

Arch Linux Plasma 5
BRE
Гость
« Ответ #67 : Март 27, 2012, 11:46 »

Ну понеслась.. "Это неправильные пчелы! Они дают неправильный мед!". Но где ж я возьму "правильных" (чтобы было точно по книжке)?  Улыбающийся Конечно я не имею права грузить Вас спецификой, но я никак не выдрючивался, не усложнял задачу, наоборот - максимально упростил как смог. Вы легко можете это проверить слегка погуглив.
Вот именно понеслась... Ты формулируешь конкретную задачу (хочу такой контейнер) - нате, думайте... Но задача уродлива с рождения. Стоит изменить условия и возможно все будет получаться лучше. Может стоит разделить контейнеты для точек и UW, может стоит объединить точки и нормали, может ...
Ну ты же не можешь нас грузить подробностями, поэтому нам остается тыкать палочкой твоего уродца.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #68 : Март 27, 2012, 11:55 »

Цитировать
А как Вы позовете такие get/set? Откуда клиент возьмет Derived:?
Тогда вместо того, чтобы писать кучу функций на каждый тип точки, разумнее (имхо) написать один класс super точки, которая бы умела себя конвертировать и в PointF и в PointD и во что ей положено по условию..
Тогда была бы всего одна функция get и одна функция set:

Код
C++ (Qt)
void set(const super_point &sp);
 
Но, если у super_point будет сответствующие конструкторы, то в метод можно будет передовать непосредственно объекты и PointF и PointD и...
Код
C++ (Qt)
set(PointF(1,2,3));
set(PointD(3,2,1));
...
 
 

Сами же наследники будут хранить вектора соответствующих типов точек, а не super_point. Супер поинт - всего лишь некий адаптер между различными связанными между собой типами точек.
« Последнее редактирование: Март 27, 2012, 12:39 от m_ax » Записан

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

Arch Linux Plasma 5
BRE
Гость
« Ответ #69 : Март 27, 2012, 13:23 »

В контейнере лежит точка 2F, клиент запрашивает 3D - он что получит. Кто это должен отслеживать? Компилятор уже не может, ты ему ручки отбил.
Пример: хранимая точка 2F (0.25f. 1.0f). Возвращаемая точка 3D (0.25, 1.0, 0.0)
Хорошо же, а.
Т.е. какой-то нерадивый программист передает в функцию контейнер с UW, хотя функция ждет нормали и она начинает их обрабатывать.
Это не пресекается не то что во время компиляции, а даже во время выполнения.
« Последнее редактирование: Март 27, 2012, 13:59 от BRE » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #70 : Март 27, 2012, 16:02 »

Но задача уродлива с рождения. Стоит изменить условия и возможно все будет получаться лучше. Может стоит разделить контейнеты для точек и UW, может стоит объединить точки и нормали, может ...
Ну ты же не можешь нас грузить подробностями, поэтому нам остается тыкать палочкой твоего уродца.
Почему уродца-то? Улыбающийся Здесь простая и естественная организация данных. Модель может иметь нормали и не иметь UV, а может и наоборот (хотя редко). Ну стало быть нормали и UV - 2 разных контейнера.

Тогда вместо того, чтобы писать кучу функций на каждый тип точки, разумнее (имхо) написать один класс super точки, которая бы умела себя конвертировать и в PointF и в PointD и во что ей положено по условию..
Тогда была бы всего одна функция get и одна функция set:
Хммм.. ну оно и сейчас примерно так и получается - близко к этому. Многочисленные конвертации можно вынести, а можно и прямо в базовом класса

Хорошо, а что же делать в случаях если понадобился "конкретный" контейнер, не устраивает общий? Напр ф-ции OpenGL требуют указателей на float или double. Здесь особых проблем нет

Код
C++ (Qt)
void DrawOpenGL( CoordVec * coord )
{
CoordVecT <Point3D> * coordD = dynamic_cast <CoordVecT <Point3D> *> (coord);
if (coord)
 glDrawFunction_d(&coordT[0].x, coordT->size());
else
 CoordVecF <Point3F> * coordF = dynamic_cast <CoordVecT <Point3F> *> (coord);
 ...
}
 
Ну и так по всем базовым типам. Не блеск конечно, но поскольку число базовых типов очень ограничено - нормально. А вот когда требуются 2 операнда "конкретных контейнера" - тогда хуже, получается громоздко
Код
C++ (Qt)
void Append( CoordVec & dst, const CoordVec & src );
CoordVec & operator = ( const CoordVec & src );
 
Не то чтобы таких очень много, но есть, и это проблема
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #71 : Март 27, 2012, 16:21 »

Цитировать
Не то чтобы таких очень много, но есть, и это проблема
Адаптер очевидно писать нужно..
Записан

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #72 : Март 27, 2012, 18:12 »

Ага, а если сделать super_point, то Append получается в неск строк - и без всяких switch. Уже хорошо! Может как-то еще лучше (без расходов на перегонку в super и обратно)?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #73 : Март 27, 2012, 18:34 »

Ага, а если сделать super_point, то Append получается в неск строк - и без всяких switch. Уже хорошо! Может как-то еще лучше (без расходов на перегонку в super и обратно)?
Цель с которой водится адаптер (или хрен знает как его назвать) заключается в том, чтобы полностью исключить в клиентском коде (в функциях внешних) все явные приведения типов и т.п. Это всё делает адаптер, а на выходе выдаёт super_point, которая уже умеет конвертить себя к другим частным PointX.
А уж вся ответственность за то, что было изначально в контэйнере и для чего предназначалось и что в результате получится в клиентском коде ложится на Вас))
Пугает какой то элемент неопределённости) Это как в рулетку играть) 
Записан

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #74 : Март 27, 2012, 18:50 »

Пугает какой то элемент неопределённости) Это как в рулетку играть)  
Есть такое, напр клиент рассчитывал на 3-ю координату, ее "физически" нет, но адаптер ее искусственно создаcт. Ну такому клиенту придется проверить Format(). Вообще на случаи 2/4 можно и забить (они встречаются в году раз) и просто считать что координат всегда 3. А вот отделаться от float/double никак не получается.

А варианта с вмещающим super_point я не видел Улыбающийся Конечно сейчас это кажется совсем простым. Спасибо (можете - когда хотите)
Записан
Страниц: 1 ... 3 4 [5] 6   Вверх
  Печать  
 
Перейти в:  


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