Runtime function selection based on the runtime type of the argument.
Let's say you have:
void Draw(box& box);
void Draw(circle& circle);
...and a
vector<unique_ptr<Shape>> shapes;
Now, you want to select the correct function for circle or box depending of the type of "shape".
You can do the correct selection using this library in this way.
dynamic_select<box, circle>(shapes[0].get(),
[](auto a)
{
draw(a);
});
Works for 1 or 2 arguments. In other words, works for double dispatching.
Virtual functions works fine in this case. Except for double dispathing.
The problem with interfaces (virtual functions) is the coupling caused by the interfaces. You cannot solve problems independently from each other; instead, you have to deal with the best set of interfaces that fits the algorithms you have so far. When you need to add or remove algorithms then you have to refactoring your interfaces for the best set again, and doing this, sometimes, can break code that is already working. It is very easy to increase coupling with interfaces, and it's hard to keep the interface sets correct. When you do it, probally the interfaces are usefull only in your especific project making your classes less reusable.
This is a prototype.
Complete sample ```cpp
using namespace std;
class object { public: virtual ~object() {} };
class box : public object { };
class circle : public object { };
void draw(const box & a) { std::cout << " draw " << typeid(a).name() << std::endl; }
void draw(const circle &a) { std::cout << " draw " << typeid(a).name() << std::endl; }
void intercept(const box & a, const circle& b) { std::cout << typeid(a).name() << " intercept " << typeid(b).name() << std::endl; }
void intercept(const circle& a, const box & b) { std::cout << typeid(a).name() << " intercept " << typeid(b).name() << std::endl; }
void intercept(const box & a, const box& b) { std::cout << typeid(a).name() << " intercept " << typeid(b).name() << std::endl; }
void intercept(const circle & a, const circle& b) { std::cout << typeid(a).name() << " intercept " << typeid(b).name() << std::endl; }
int main() { std::vectorstd::unique_ptr<object> v; v.emplaceback(new box()); v.emplaceback(new circle());
for (auto& item : v)
{
dynamic_select<box, circle>(item.get(),
[](auto a)
{
draw(a);
});
}
//Double dispatch
for (auto& item : v)
{
dynamic_select<box, circle>(v[1].get(),
item.get(),
[](auto a, auto b)
{
intercept(a, b);
});
}
}
output
draw class box draw class circle class circle intercept class box class circle intercept class circle ```
dynamic_select.h ```cpp
template< class... Tn>
struct Gen2
{
template
template
template< class... Tn>
struct Gen
{
template
template<class A1, class A2, class F>
Gen(const A1* a1, const A2* a2, F)
{
}
};
template
template<class A1, class A2, class F>
Gen(const A1 * a1, const A2* a2, F f)
{
if (typeid(T1) == typeid(*a1))
{
if (typeid(T1) == typeid(*a2))
{
f(dynamic_cast<const T1&>(*a1),
dynamic_cast<const T1&>(*a2));
}
else
{
Gen2<T1, Tn...>(a1, a2, f);
}
}
else
{
Gen<Tn...>(a1, a2, f);
}
}
};
template
template<class A1, class A2, class F>
dynamic_select(const A1 * a1, const A2* a2, F f)
{
Gen<Tn..., Tn...>(a1, a2, f);
}
};
##See also
[type_ptr3.htm](type ptr) Not using C++ rtti.
##Notes
Compiled with:
Visual C++ Compiler Nov 2013 CTP (CTP_Nov2013)