Boost logo

Geometry :

Subject: Re: [geometry] generic for_each and num proposal
From: Barend Gehrels (barend_at_[hidden])
Date: 2013-07-29 17:46:36

Hi Mats,

On 29-7-2013 19:41, Mats Taraldsvik wrote:
> Hi Barend,
> On 07/28/2013 07:59 PM, Barend Gehrels wrote:
>> Hi Mats,
>> On 28-7-2013 12:23, Mats Taraldsvik wrote:
>>> Hi,
>>> On 07/26/2013 11:54 PM, Michael Winkelmann wrote:
>>> It would be very useful to expand on the for_each algorithms.
>>> However, as I understand the boost.geometry documentation and your
>>> proposal, there is a subtle but important difference: the current
>>> for_each_point algorithm work on a point _concept_, while your
>>> for_each<point> algorithm work on a concrete point type (in this
>>> case bg::model::d2::point_xy<double>.
>> I don't see why this would not work for concepts?
>>> What if I used e.g. std::pair to represent points? I'd have to
>>> remember the exact type used for points in the
>>> polygon/ring/linestring/segment... I might have two polygons that
>>> represents points in differents ways, and then I'd have to implement
>>> the algorithm twice (for_each<bgm::d2::point_xy<double>> and
>>> for_each<std::pair<double,double>>.
>>> I'm not sure if this is solvable in the generic case until we get
>>> proper Concepts (lite), which, combined with generic lambdas would
>>> make a concepts-based interface.
>> OK now I see what you mean. The proposal has probably to be read as:
>> size_t a = num<ring*_tag*>(myPolygon); // Returns number of rings in
>> polygon
>> size_t b = num<segment*_tag*>(myRing); // Returns number of segments
>> in ring
>> size_t c = num<polygon*_tag*>(myPolygon); // Should return 1
>> The tag's are mostly used internally, if used externally, they could
>> (maybe) be namespaced e.g.
>> size_t a = num<*geometry_type::*ring>(myPolygon); // Returns number
>> of rings in polygon
>> (don't know if this name is appropriate, just an idea)
> I'm sorry, I could have been more clear (and I might simply be wrong
> :) ). I think the num-part of the proposal is fine with *_tag as
> template arguments. As long as the actual algorithm is written with
> the operations required by the point concept, it should work for every
> type that satisfies the point concept. And it is very useful indeed! :)
> Sorry if I come across as negative with my (hopefully constructive)
> criticism, I'm trying not to be. :)

No problem, no worries, thanks for your reaction - it certainly helped
to make things clear. So it was constructive :-)
Thanks for your new mail too.

> What I'm concerned with is the lambda argument to the for_each<*_tag>
> algorithms. I'm not aware of a way to write a lamdba in terms of a
> (geometry) concept, so they will be type-specific instead of
> concept-specific. Which means they have to be tailored to the type of
> the point/linestring/polygon etc. -- not the concept (which is ideal).
> Consider a Polygon that has four points of different types:
> bgm::d2::point_xy<double> point1
> std::pair<double, double> point2
> bgm::d2::point_xy<double> point3
> std::pair<double, double> point4
> How do you write the for_each<point_tag> where the lambda is able to
> capture all four points? One could use a boost::variant or similar
> structure to account for all point types, but it isn't ideal, is it?
> (However, this might be the best solution for current C++(?))

Good point. Lambda's are written in a context, so the program or
function or class-method or whatever. So if you have a main program, you
use the point-type you define. Because the lambda is programmed and used
only once you specify the type you need. These lambda's are never reused
for other type. If you are in a template function or class, you can
simply use the template-argument (which can be of any point-type, as
long as it follows the context). So it all follows normal rules, only
the lambda-function itself is not templated but does not need to be.
This all is not really related to Boost.Geometry and also applies for

So it is possible; variants are not necessary.

I attached two programs (based on something I already had) to show these
both uses. So it (the template version) works for any Concept. In the
non-template version, it is simply not relevant to tailor it for many
types (and not possible indeed).

> Also, what if we decided to have some pre-defined lambdas/functions
> that one could use with for_each<*_tag>? They'd have to be generic
> (i.e. concepts-based) to be truly useful and universally applicable...
>> What do you mean by Concept (lite)?
> Concept[s] lite is the current proposal for constraining templates,
> and, by extension, generic lambdas (c++14). It is planned as a TS in
> the C++14 timeframe, as far as I know. The latest version is N3701,
> look at the summer standards papers mailing [1] -- I think it is
> really interesting, I think it is worth a look if you are not familiar
> with it already.

I was not aware of the "lite" addition. OK, so this looks like the
Concepts, postponed in C++11.
Boost.Geometry uses concepts and checks it by Boost Concept Check
Library (BCCL).

> I think this would allow the behaviour I am seeking:
> for_each<point_tag>( aPolygon, [](PointConcept point)
> {
> ...
> });

Here, you can make use of the type of the aPolygon parameter (either a
concrete type or a template), and then use (as soon as for_each is
tagged, for now: for_each_point):
             [](boost::geometry::point_type<polygon>::type const& p)

> or, a pre-defined function
> auto point_to_wgs84(PointConcept point)
> {
> ...
> }
> ...
> for_each<point_tag>(anotherPolygon, point_to_wgs84);

This is also already possible (with for_each_point, without point_tag).
You have to specify the template argument explicitly in the call (and
note you are missing template <typename PointConcept> in your function
definition). But that is no problem - it might even be a
template/concept (like with lambdas). This variant is listed in the help:

Regards, Barend

Geometry list run by mateusz at