Boost logo

Boost :

From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2008-05-05 18:31:25


I've been working on an idea for using some compile time concept type
introspection and tag dispatching to allow generically named free
functions (such as contains()) to compile and work in user code when
called with any sensible combination of geometry types. This should
make user code much more concise than with my current design; all the
concept related boilerplate can be dispensed with.

//should compile
bool result1 = contains(rectangle1, rectangle2);
//should compile
bool result2 = contains(rectangle1, point);
//should compile
bool result3 = contains(interval1, interval2);
//should compile
bool result4 = contains(interval1, coordinate_value);
//should not compile because it is non-sensical
bool result5 = contains(rectangle1, interval1);
//should not compile because it is non-sensical
bool result6 = contains(coordinate_value, point1);

The idea is that a geometry_traits struct be specialized for each
geometry data type such that it provides a typedef for the related
geometry concept. That typedef can be inspected at compile time to
provide type introspection and passed as a tag value for tag
dispatching. See example code pasted below.

The one problem with this scheme is that it doesn't allow a user type to
model more than one geometry type. That means that if someone models
point with std::pair<int, int> it makes it impossible for someone else
to model interval with std::pair<int, int> anywhere where the
declaration of the one for point is visible. I consider that to be a
good thing because it enforces type safety on user types, since you lose
the protection of the compiler from inadvertently using point data as
interval data if you model std::pair<int, int> as both. However, people
eager to use tuple for all of their applicable geometry data types
should take note of this limitation.

Do you guys prefer this scheme to what I showed in example3.cpp?

Thanks,
Luke

//some point related code omitted

struct rectangle_concept {
  template <typename rectangle_type, typename rectangle_type2>
  static bool contains_dispatch(const rectangle_type& rectangle, const
rectangle_type2 rectangle_contained, rectangle_concept tag) {
    std::cout << "rectangle contains rectangle\n";
  }
  template <typename rectangle_type, typename point_type>
  static bool contains_dispatch(const rectangle_type& rectangle, const
point_type point_contained, point_concept tag) {
    std::cout << "rectangle contains point\n";
  }
  template <typename rectangle_type, typename geometry_type>
  static bool contains(const rectangle_type& rectangle, const
geometry_type& contained_geometry_object);
};

struct no_type {};

template <typename T>
struct geometry_traits {
  typedef no_type geometry_concept;
};

template <>
struct geometry_traits<point_data<int> > {
  typedef point_concept geometry_concept;
};
template <>
struct geometry_traits<rectangle_data<int> > {
  typedef rectangle_concept geometry_concept;
};

template <typename rectangle_type, typename geometry_type>
bool rectangle_concept::contains(const rectangle_type& rectangle, const
geometry_type& contained_geometry_object) {
  //disambiguate function to call through tag dispatching
  return rectangle_concept::contains_dispatch(rectangle,
contained_geometry_object, typename
geometry_traits<geometry_type>::geometry_concept());
}

//function that should copile for any two geometry types that may have a
containment relationship
template <typename geometry_type_1, typename geometry_type_2>
bool contains(const geometry_type_1& geometry_object, const
geometry_type_2& contained_geometry_object) {
  //select function to call through introspection
  typename geometry_traits<geometry_type_1>::geometry_concept
concept_instantiation;
  return concept_instantiation.contains(geometry_object,
contained_geometry_object);
}

void foo() {
  rectangle_data<int> rect1, rect2;
  point_data<int> point;
  rectangle_concept::contains(rect1, point);
  rectangle_concept::contains(rect1, rect2);
  contains(rect1, point);
  contains(rect1, rect2);
}

output from calling foo():
rectangle contains point
rectangle contains rectangle
rectangle contains point
rectangle contains rectangle


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk