- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
class figure
{
//...
};
class triugolnik: public figure
{
//...
};
class kvadrat: public figure
{
//...
};
#define PAIR(f0, f1) std::make_tuple(std::type_index(typeid(f0)), std::type_index(typeid(f1)))
int PloshadTrehFigur(const figure& f0, const figure& f1, const figure& f2);//forward declaration
int PloshadDvuhFigur(const figure& f0, const figure& f1)
{
static const std::unordered_map<
std::tuple<std::type_index, std::type_index>, std::function<int(const figure&, const figure&)>
> caller
{
{PAIR(triugolnik, kvadrat), ploshadTriugolnikIKvadrat},
{PAIR(kvadrat, triugolnik), lispGovno::flip(ploshadTriugolnikIKvadrat)},
{PAIR(kvadrat, kvadrat), ploshadKvadratIKvadrat},
{PAIR(triugolnik, triugolnik), ploshadTriugolnikITriugolnik}
};
const auto& f = caller.find(PAIR(f0, f1));
assert(f!=caller.end());
f(f0, f1);
}
#undef PAIR
К примеру, в данной схеме нельзя написать "обобщенные" версии функции, у которых в аргумент может приходить не только некий класс, но и все его потомки. Это спасло бы от квадратичного разрастания, если функции для работы вполне хватает базового класса: А диспетчеризация по "специфичности", емнип, одна из основных фич мультиметодов ;)
Но пацаны, как всегда, не обратили внимания на это визгливое кукареканье. Пусть кукарекает, что с него взять?
Петух — не человек, и сегодня ему предстоит очень трудная ночь. У него уже в течение полутора лет каждая ночь была очень трудной, и теперь его анус был разработан настолько, что он без труда мог спрятать в нём банку сгущёнки.
О да, n^2 квадратичное, а n*(n-1)/2 не квадратичное...
> Неквадратичное говно сможешь написать
Х.з. Мап там уже не поюзать, т.к. участвует неизвестное количество сабклассов. Для проверки можно было бы сделать что-то типа обхода списка с динамик кастами... А вот специфичность так просто не проверить... По крайней мере я не могу придумать проверку, не требующую вносить что-то в сами классы. Заставлять программиста писать самые специфичные функции сверху или снизу не хочется.
А отсортировать сами классы по специфичности во время компиляции?
А как? В крестах же иерархию классов ни при компиляции (т.к. они могут быть в других файлах и даже дллках), ни даже в рантайме не выяснить. Можно только проверить факт наследования через dynamic_cast, да реальный тип через typeid...
Имея ссылку на figure легко проверить, является ли оно rectangle или polygon, но вот понять, что rectangle более специфичный чем polygon - никак.
Остается только руками добавлять в классы дополнительную инфу, например std::type_index родителя (если забить на множественное наследование) ;(
Например пусть у нас есть:
(polygon, polygon) - универсальная функция
(rectangle, polygon), (polygon, rectangle) - более быстрые реализации
Тогда (rectangle, triangle) заматчится с (rectangle, polygon) после апкаста triangle в polygon. В мап добавится (rectangle, triangle), ссылающийся на ту же ф-ю что и (rectangle, polygon).
А в (triangle, rectangle) апкаст правой части не даст ничего, поэтому апкастим левый, и получаем (polygon, rectangle). В мап добавится (triangle, rectangle) ссылающийся на функцию от (polygon, rectangle).
А зачем это выяснять? У тебя есть список функций, обрабатывающих пары или тройки и тд. Вытащил из них сигнатуры. Из сигнатур вытащил типы параметров. Отсортировал их по специфичности. Дальше уже дело в шляпе. Наверное O(1) при такой постановке задачи уже не получится сделать, хотя надо подумать. Но иерархии обычно не большие, так что это не проблема.
Как? Я же не могу узнать кто там от кого порожден. Даже в рантайме. Ну вот только если программист будет добавлять некую инфу о родителях класса вручную.
> Наверное O(1) при такой постановке задачи уже не получится сделать
Да хуй с ним с O(1) :) Даже в CL это поиск с последующим кешированием.
Только топосорт, где в качестве отношения - приводимость
Я пока вижу только одно решение руками (например макросом PARENTS(foo, bar)) или досборочным скриптом прикручивать к классам дополнительную инфу...
Ну и сортировка очень плохо сочетается с динамически подгружаемым кодом.
Если я ничего не путаю в вашей беседе, то std::is_convertible должен сойти. В гениальных плюсах правда могут быть циклы в операциях приведения: a конвертится в b, b конвертится в a, т.е. это отношение уже не является отношением weak ordering
Видел?
Я люблю реализовывать операторы языка каждый день. У операторов С++ есть один фатальный недостаток. Создатели компилятора слишком тупые. А я свободный от задротства человек, успешен по жизни и реализую операторы языка 3 раза в день.
Зачем это им вообще было нужно? В компиляторе не так часто нужно кастить типы. Оптимизация рут о эвил головного мозга?
Не удивлюсь, если эта библиотека не умеет в специфичные мультиметоды, не умеет во множественное и виртуальное наследование и ещё что-нибудь.
Я не верю. Потому считаю, что незамысловатый ограниченный в возможностях велик как правило лучше громоздких универсальных решений и ближе к телу.
Ты меня затролил. И ты везде прав.
Из моего арканоида.
При этом TagPair устроен так, что TagPair<Bullet,Alga>, например, тупо не скомпилируется, это даст контроль над зеркальными парами.
>>ploshadTriugolnikITriugolnik
Блджад, немедленно развидеть это!!!
У меня ТРИУГОЛЬНИК от такого безграмотного транслита.
P.S. Translyt - bezgramotnoie govno po umolchaniju :)