Union, Tangencies and Colors
I like the picture below very much.
Boost.Geometry is a generic C++ library for geometry. Boost is a well-known peer-reviewed Open Source library collection for C++.
struct citrus_tag {};
struct pome_tag {};
struct apple_tag : pome_tag {};
struct pear_tag : pome_tag {};
struct banana_tag {};
struct orange_tag : citrus_tag {};
struct lemon_tag : citrus_tag {};
struct lime_tag : citrus_tag {};
template <typename T> struct tag {};
template <> struct tag<apple> { typedef apple_tag type; };
template <> struct tag<pear> { typedef pear_tag type; };
template <> struct tag<orange> { typedef orange_tag type; };
template <> struct tag<lime> { typedef lime_tag type; };
template <> struct tag<banana> { typedef banana_tag type; };
template
<
typename Tag, typename BaseTag,
typename BT2 = void, typename BT3 = void, typename BT4 = void,
typename BT5 = void, typename BT6 = void, typename BT7 = void
>
struct tag_cast
{
typedef typename boost::mpl::if_
<
typename boost::is_base_of<BaseTag, Tag>::type,
BaseTag,
// Try next one in line:
typename tag_cast<Tag, BT2, BT3, BT4, BT5, BT6, BT7, void>::type
>::type type;
};
template <typename Tag>
struct tag_cast<Tag, void, void, void, void, void, void, void>
{
// If not found, take specified tag, so do not cast
typedef Tag type;
};
namespace dispatch
{
template <typename T> struct has_vesicles : boost::false_type {};
template <> struct has_vesicles<citrus_tag> : boost::true_type {};
}
template <typename Fruit>
std::string has_vesicles(Fruit const& fruit)
{
// (Potentially) go up in hierachy: take tag corresponding to Fruit,
// downcast to citrus_tag if possible
typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag>::type tag;
return std::string("has vesicles: ")
+ (dispatch::has_vesicles<tag>::value ? "true" : "false");
}
typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag, pome_tag>::type tag;
will result in a citrus_tag if it is a citrus, a pome_tag if it is a
pome, and otherwise it results in the input tag. Besides this, it also
walks through a tag
hierarchy, so if citrus_tag and pome_tag were both derived from, e.g.,
a rosid_tag,
and rosid_tag was specified in this call, it would result in a
rosid_tag. int main()
{
using namespace fruit;
apple a("my apple");
pear p("my pear");
orange o("my orange");
std::cout << has_vesicles(a) << std::endl;
std::cout << has_vesicles(p) << std::endl;
std::cout << has_vesicles(o) << std::endl;
return 0;
}
struct multi_tag;
struct multi_point_tag : multi_tag {};
struct multi_linestring_tag : multi_tag {};
struct multi_polygon_tag : multi_tag {};
struct multi_tag;
struct multi_point_tag : multi_tag {};
struct multi_linestring_tag : multi_tag, linear_tag {};
struct multi_polygon_tag : multi_tag, areal_tag {};
When calling tag_cast, the results depends on the order of the
specified base tags. And so does the dispatching.struct apple_tag {};
struct banana_tag {};
struct orange_tag {};
struct apple
{
double radius;
std::string name;
apple(std::string const& n) : name(n) {}
};
struct banana
{
double length;
std::string name;
banana(std::string const& n) : name(n) {}
};
All this is quite simple C++ code, though you have to understand
templates (generics) and specialization.namespace dispatch
{
void eat(apple const& a, apple_tag)
{
std::cout << "bite" << std::endl;
}
void eat(banana const& b, banana_tag)
{
std::cout << "peel" << std::endl;
}
}
template <typename T>
void eat(T const& fruit)
{
typename tag<T>::type the_tag;
dispatch::eat(fruit, the_tag);
}
The function eat
at the bottom
first declares an instance of the tag. If an apple is entered in this
function, it will be an instance of the apple_tag. If a banana is
entered, it is a banana_tag. Then it forwards its call to the eat
function in the namespace dispatch. There are two versions (overloads)
there, one specified with an apple_tag, one with a banana_tag. The
compiler selects, based on the tag
the right function. Quite easy, and quite powerful,
this tag dispatching system.namespace dispatch
{
template <typename Tag> struct eat {};
template <> struct eat<apple_tag>
{
static void apply(apple const& a)
{
std::cout << "bite" << std::endl;
}
};
template <> struct eat<banana_tag>
{
static void apply(banana const& b)
{
std::cout << "peel" << std::endl;
}
};
}
template <typename T>
void eat(T const& fruit)
{
dispatch::eat<typename tag<T>::type>::apply(fruit);
}
int main()
{
apple a("my apple");
banana b("my banana");
eat(a);
eat(b);
return 0;
}
It is the same for the instance-version and the type-version. template <typename Tag> struct spherical {};
template <> struct spherical<apple_tag>
{
static const bool value = true;
};
template <> struct spherical<banana_tag>
{
static const bool value = false;
};
template <typename T>
struct spherical
{
static const bool value = dispatch::spherical<typename tag<T>::type>::value;
};