#ifndef MULTIDISPATCHER2_H_INCLUDED
#define MULTIDISPATCHER2_H_INCLUDED
#include <map>
#include <typeinfo>
/**
@param ReturnType - type of the return value of handler functions
@param T1, T2 - base types for dispatching types
@param default_callback_func - default handler if there is no dispatch for such types
*/
template<
typename ReturnType,
typename T1,
typename T2,
ReturnType(*default_callback_func)(T1&, T2&)
>
class Dispatcher2
{
private:
// Map key
struct TypeInfo
{
const std::type_info& ti1;
const std::type_info& ti2;
TypeInfo(const std::type_info& _ti1, const std::type_info& _ti2):
ti1(_ti1), ti2(_ti2)
{
}
bool operator == (const TypeInfo& typeinfo) const
{
return (ti1==typeinfo.ti1 && ti2==typeinfo.ti2);
}
};
struct TypeInfoComp : public std::binary_function<const TypeInfo&, const TypeInfo&, bool>
{
bool operator () (const TypeInfo& t1, const TypeInfo& t2) const
{
return t1.ti1.before(t2.ti1) || (!(t2.ti1.before(t1.ti1)) && t2.ti2.before(t1.ti2));
}
};
typedef TypeInfo KeyType;
// Map value
typedef ReturnType(*CallbackType)(T1&, T2&);
// Map itself
typedef std::map<KeyType, CallbackType, TypeInfoComp> MapType;
MapType callbacks;
public:
Dispatcher2()
{
}
/**
add dispatch callback
@param CT1, CT2 - concrete types (dispatching pair)
*/
template<typename CT1, typename CT2, ReturnType(*callback)(CT1&, CT2&)>
void add()
{
const KeyType key(typeid(CT1), typeid(CT2));
struct Local
{
static ReturnType trampoline(T1& t1, T2& t2)
{
return callback(
dynamic_cast<CT1&>(t1),
dynamic_cast<CT2&>(t2)
);
}
};
callbacks[key] = &Local::trampoline;
}
void clear()
{
callbacks.clear();
}
ReturnType run(T1 &t1, T2 &t2)
{
try
{
// check if dispatcher callback is registered
const KeyType key(typeid(t1), typeid(t2));
typename MapType::iterator i = callbacks.find(key);
if (i != callbacks.end())
{
return (*i).second(t1,t2);
}
}
catch (std::exception& e)
{
}
return default_callback_func(t1, t2);
}
ReturnType run(T1 *t1, T2 *t2)
{
return run(*t1, *t2);
}
};
#endif // MULTIDISPATCHER2_H_INCLUDED
|
| _Winnie C++ Colorizer |
Usage:
struct Thing {
virtual ~Thing() {}
};
struct Rock : Thing {};
struct Paper : Thing {};
struct Scissors : Thing {};
bool Thing_Thing(Thing&, Thing&) { cout << " (T:T) "; return false; }
bool Paper_Rock(Paper&, Rock&) { cout << " (P:R) "; return true; }
bool Rock_Scissors(Rock&, Scissors&) { cout << " (R:S) "; return true; }
bool Sciccors_Paper(Scissors&, Paper&) { cout << " (S:P) "; return true; }
int main(int, char **)
{
Dispatcher2<bool, Thing, Thing, Thing_Thing> compare;
compare.add<Paper, Rock, Paper_Rock>();
compare.add<Rock, Scissors, Rock_Scissors>();
compare.add<Scissors, Paper, Sciccors_Paper>();
Thing* paper = new Paper();
Thing* rock = new Rock();
std::cout << std::boolalpha;
std::cout << "Paper : Rock " << compare.run(paper, rock) << std::endl;
std::cout << "Rock : Paper " << compare.run(rock, paper) << std::endl; |
| _Winnie C++ Colorizer |
Есть и такая реализация: http://blog.emptycrate.com/node/288
2010-03-04 06:00 pm (UTC)
2010-03-04 08:24 pm (UTC)
В моей реализации шаблон Dispatcher2 ищет тот и только тот обработчик, который соответствует запрошенному кортежу типов. Если не найден подходящий кортеж, вызывается default callback (см. 4-й параметр шаблона Dispatcher2).
2010-03-04 08:58 pm (UTC)
В качестве примера можно рассмотреть пересечение геометрических фигур: Rectangle>Polygon>Shape, Circle>Curve>Shape. Имеют смысл все функции вида Intersect(X,Y), но Intersect(Rectangle,Rectangle), скажем, значительно эффективнее, чем Intersect(Shape,Shape). Поэтому стоит выбрать самую специализированную функцию.
Никакого другого способа, подходящего под характеристику «правильно работает с наследованием», я вообразить не могу.
Как это все реализовать за логарифмическое время — вопрос отдельный.
Примерно аналогичная ситуация имеется при выборе функции из набора перегруженных функций. Там отношение порядка другое, но функция выбирается по такому же принципу (наилучшее совпадение по всем параметрам).
2010-03-05 11:40 am (UTC)
2010-03-05 01:06 pm (UTC)
2010-03-05 07:17 pm (UTC)
2010-03-05 08:36 pm (UTC)
2010-03-06 12:48 am (UTC)
Если у Вас есть готовое решение, чтоб работало наследование, поделитесь ссылкой или кодом.
У меня есть идеи, как это сделать и как это сделать эффективно, интересно посмотреть, что из этого получится.
2010-03-06 11:29 am (UTC)
Нет, готового решения нет, надо сидеть писать.
2010-07-11 09:26 am (UTC)
2010-07-11 09:27 am (UTC)
2010-07-11 09:27 am (UTC)
2010-07-11 09:27 am (UTC)
2010-07-11 12:31 pm (UTC)
2010-07-11 06:29 pm (UTC)
2010-09-12 08:21 pm (UTC)
2010-09-17 07:00 pm (UTC)