$include_dir="/home/hyper-archives/geometry/include"; include("$include_dir/msg-header.inc") ?>
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 
std::for_each.
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::for_each<point_tag>
         (
             aPolygon,
             [](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:
http://www.boost.org/doc/libs/1_54_0/libs/geometry/doc/html/geometry/reference/algorithms/for_each/for_each_point.html 
(list_coordinates)
Regards, Barend