[fusion] Support for classic boost::tuple

Hi, Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc. Now there are 3 adapted sequences: 1) std::pair 2) boost::array 3) boost::tuples::tuple And, from the start, of course all MPL sequences are full fusion citizens too. I hope more boost libraries can be "fusion-ified" :) Have fun!!! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair
This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is pair<int*,int*> a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair
This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is
pair<int*,int*>
a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)?
Both? I think, in as much as boost::array<int> is a dynamic sequence that STL algorithms can operate on, and at the same time, is also a static sequence fusion algorithms can handle, the same should be true for mono-sequences like pair<int*,int*>. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is
pair<int*,int*>
a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)?
Both? I think, in as much as boost::array<int> is a dynamic sequence that STL algorithms can operate on, and at the same time, is also a static sequence fusion algorithms can handle, the same should be true for mono-sequences like pair<int*,int*>.
Oh and BTW, such a unified library is a *cool* idea! It will finally complete the landscape from fully static (MPL) to fully dynamic (STL). Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair
This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is
pair<int*,int*>
a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)?
Both? I think, in as much as boost::array<int> is a dynamic sequence that STL algorithms can operate on, and at the same time, is also a static sequence fusion algorithms can handle, the same should be true for mono-sequences like pair<int*,int*>.
[what's a mono-sequence?] It's not the same thing at all. In the case of array<int>, the sequence has the same elements in either case; we're just talking about two ways of accessing the same sequence. In the case of std::pair there are two completely distinct interpretations, either of which could be valid. In my case I think there are only two possible choices: 1. say that std::pair needs to be wrapped or otherwise transformed before I know how to treat it. 2. pick one of the two interpretations. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is
pair<int*,int*>
a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)? Both? I think, in as much as boost::array<int> is a dynamic sequence that STL algorithms can operate on, and at the same time, is also a static sequence fusion algorithms can handle,
David Abrahams wrote: the same should be true for mono-sequences like pair<int*,int*>.
[what's a mono-sequence?]
The opposite of hetero-sequence :P
It's not the same thing at all. In the case of array<int>, the sequence has the same elements in either case; we're just talking about two ways of accessing the same sequence. In the case of std::pair there are two completely distinct interpretations, either of which could be valid. In my case I think there are only two possible choices:
1. say that std::pair needs to be wrapped or otherwise transformed before I know how to treat it.
2. pick one of the two interpretations.
I'm sorry. I think I'm lost. With: pair<int*,int*> or tuple<int*,int*,int*,int*> or array<int*> I see the same elements. What am I missing? Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
[what's a mono-sequence?]
The opposite of hetero-sequence :P
A mono-sequence is the opposite of a multi-sequence. The opposite of a hetero-sequence is a homo-sequence.
It's not the same thing at all. In the case of array<int>, the sequence has the same elements in either case; we're just talking about two ways of accessing the same sequence. In the case of std::pair there are two completely distinct interpretations, either of which could be valid. In my case I think there are only two possible choices:
1. say that std::pair needs to be wrapped or otherwise transformed before I know how to treat it.
2. pick one of the two interpretations.
I'm sorry. I think I'm lost. With:
pair<int*,int*>
or
tuple<int*,int*,int*,int*>
or
array<int*>
I see the same elements. What am I missing?
* Boost.Range and Boost.Fusion both interpret an int*[4] as a sequence of 4 values of type int*. Consistent * Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*. * Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
[what's a mono-sequence?] The opposite of hetero-sequence :P
A mono-sequence is the opposite of a multi-sequence. The opposite of a hetero-sequence is a homo-sequence.
Oh my, yeah. I thought all along that was what I typed! Must still be sleepy, or cross-eyed, or both :P
It's not the same thing at all. In the case of array<int>, the sequence has the same elements in either case; we're just talking about two ways of accessing the same sequence. In the case of std::pair there are two completely distinct interpretations, either of which could be valid. In my case I think there are only two possible choices:
1. say that std::pair needs to be wrapped or otherwise transformed before I know how to treat it.
[...]
* Boost.Range and Boost.Fusion both interpret an int*[4] as a sequence of 4 values of type int*. Consistent
* Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*.
* Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int.
Oh man, Now I see the problem. Pardon my slowness!!! Well, it seems, this interpretation of Boost.Range for pair<T*,T*> (or in general, std::pair<iterator,iterator> is at the very least suspicious. If we all agree that pair<T,T> is a tuple (a sequence in Fusion's sense), then pair<T*,T*> shouldn't be any different. I'd say that treating std::pair<iterator,iterator> as a runtime sequence is the wrong generalization. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
David Abrahams wrote:
* Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*.
* Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int.
Oh man, Now I see the problem. Pardon my slowness!!! Well, it seems, this interpretation of Boost.Range for pair<T*,T*> (or in general, std::pair<iterator,iterator> is at the very least suspicious. If we all agree that pair<T,T> is a tuple (a sequence in Fusion's sense), then pair<T*,T*> shouldn't be any different. I'd say that treating std::pair<iterator,iterator> as a runtime sequence is the wrong generalization.
It cannot be helped. std::equal_range returns a std::pair<iterator,iterator>. You'll have to argue with Stepanov about it. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Joel de Guzman wrote:
David Abrahams wrote:
* Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*.
* Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int. Oh man, Now I see the problem. Pardon my slowness!!! Well, it seems, this interpretation of Boost.Range for pair<T*,T*> (or in general, std::pair<iterator,iterator> is at the very least suspicious. If we all agree that pair<T,T> is a tuple (a sequence in Fusion's sense), then pair<T*,T*> shouldn't be any different. I'd say that treating std::pair<iterator,iterator> as a runtime sequence is the wrong generalization.
It cannot be helped. std::equal_range returns a std::pair<iterator,iterator>.
So what?
You'll have to argue with Stepanov about it.
Did he intend to regard std::pair<iterator,iterator> as a runtime sequence? Is it written in the standard that a std::pair<iterator,iterator> is a model of a Sequence? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
* Boost.Range and Boost.Fusion both interpret an int*[4] as a sequence of 4 values of type int*. Consistent
* Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*.
* Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int.
Oh man, Now I see the problem. Pardon my slowness!!! Well, it seems, this interpretation of Boost.Range for pair<T*,T*> (or in general, std::pair<iterator,iterator> is at the very least suspicious. If we all agree that pair<T,T> is a tuple (a sequence in Fusion's sense), then pair<T*,T*> shouldn't be any different. I'd say that treating std::pair<iterator,iterator> as a runtime sequence is the wrong generalization.
I disagree. There's no "wrong" here. It's going to be very common that in two different well-designed generic libraries, one 3rd party type plays different two different roles. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
* Boost.Range and Boost.Fusion both interpret an int*[4] as a sequence of 4 values of type int*. Consistent
* Boost.Fusion interprets a pair<int*,int*> as a sequence of two values of type int*.
* Boost.Range interprets a pair<int*,int*> x as a sequence of x.second-x.first values of type int. Oh man, Now I see the problem. Pardon my slowness!!! Well, it seems, this interpretation of Boost.Range for pair<T*,T*> (or in general, std::pair<iterator,iterator> is at the very least suspicious. If we all agree that pair<T,T> is a tuple (a sequence in Fusion's sense), then pair<T*,T*> shouldn't be any different. I'd say that treating std::pair<iterator,iterator> as a runtime sequence is the wrong generalization.
I disagree. There's no "wrong" here. It's going to be very common that in two different well-designed generic libraries, one 3rd party type plays different two different roles.
In my honest opinion... Pairs, triples, quadruples etc. are tuples. Other interpretations of that generalization, IMO, are bogus -- especially one that gives special meaning to pair<iterator,iterator> as a runtime sequence. A pair<iterator,iterator> and an iterator_range<iterator> are different beasts. The first is a tuple comprising 2 iterator elements and the other is an, ehmm, an iterator range. Making them behave similarly, confuses pair's intended meaning and leads to conceptual problems such as the one you posed. Here's another problem: std::map<int*, int*> m; generic code that treats pair<int* int*> as an iterator_range will treat m's data type incorrectly. To me it's like, generalizing that something with a wing, a propeller, and all things that comprise an airplane-- is an airplane. No, not necessarily. The presence of these elements do not complete the picture. It can be, say, *just a collection of parts*. Hence, pair<iterator,iterator> is just a collection of 2 iterators, nothing more. All that being said, I don't care too much either way. It's not a concern of Fusion, AFAICT. Unless, you are asking for std::pair to be removed from the list of supported Fusion sequences? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman <joel@boost-consulting.com> writes:
Here's another problem:
std::map<int*, int*> m;
generic code that treats pair<int* int*> as an iterator_range will treat m's data type incorrectly.
No, generic code doesn't look at types and say, "which of two concepts with no refinement relationship does this type fulfill?" and then take different actions based on the answer. The only such type-based dispatching in generic code comes through algorithm specialization: "this type fulfills concept X, but also concept Y which is a refinement of X, so I'll use that information to do whatever I was going to do more efficiently." -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Here's another problem:
std::map<int*, int*> m;
generic code that treats pair<int* int*> as an iterator_range will treat m's data type incorrectly.
No, generic code doesn't look at types and say, "which of two concepts with no refinement relationship does this type fulfill?" and then take different actions based on the answer.
Sometimes it does. Consider serialization, or stream output. You could have if( type is a range ) output sequence of values else output something else Treating pair<pointer, pointer> as a range creates an ambiguity here.

Peter Dimov wrote:
David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Here's another problem:
std::map<int*, int*> m;
generic code that treats pair<int* int*> as an iterator_range will treat m's data type incorrectly. No, generic code doesn't look at types and say, "which of two concepts with no refinement relationship does this type fulfill?" and then take different actions based on the answer.
Sometimes it does. Consider serialization, or stream output. You could have
if( type is a range )
output sequence of values
else
output something else
Treating pair<pointer, pointer> as a range creates an ambiguity here.
And potentially dangerous too. first and last might not be valid, they may point to separate single elements (e.g. heap objects), or arrays from different locations, or combinations thereof. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On Fri, Sep 29, 2006 at 11:58:48AM -0400, David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Here's another problem:
std::map<int*, int*> m;
generic code that treats pair<int* int*> as an iterator_range will treat m's data type incorrectly.
No, generic code doesn't look at types and say, "which of two concepts with no refinement relationship does this type fulfill?" and then take different actions based on the answer. The only such type-based dispatching in generic code comes through algorithm specialization: "this type fulfills concept X, but also concept Y which is a refinement of X, so I'll use that information to do whatever I was going to do more efficiently."
The problem here is that there is one concept, namely a runtime sequence, that pair<int*,int*> fulfills in two unrelated ways. So generic code does need to be able to decide which way to interpret it. Or the concepts of iterator_range and runtime sequence have to be separated, which is unfortunate, since iterator_range is a very natural refinement of a runtime sequence. Geoffrey

Joel de Guzman <joel@boost-consulting.com> writes:
To me it's like, generalizing that something with a wing, a propeller, and all things that comprise an airplane-- is an airplane. No, not necessarily. The presence of these elements do not complete the picture. It can be, say, *just a collection of parts*. Hence, pair<iterator,iterator> is just a collection of 2 iterators, nothing more.
External, non-intrusive, adaptation of a 3rd party type to make it model a particular concept that it doesn't model "inherently" is a fundamental generic programming maneuver. I don't see anything particularly wrong with making a pair of iterators model Range. Jeremy Siek has described cases to me wherein one type can play two different roles with the *same* library. For that you need two different concept maps, to map the type into its different roles. Thus his recent "scoped concept_map" proposal.
All that being said, I don't care too much either way. It's not a concern of Fusion, AFAICT. Unless, you are asking for std::pair to be removed from the list of supported Fusion sequences?
Nope. Just raising the point for discussion. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
To me it's like, generalizing that something with a wing, a propeller, and all things that comprise an airplane-- is an airplane. No, not necessarily. The presence of these elements do not complete the picture. It can be, say, *just a collection of parts*. Hence, pair<iterator,iterator> is just a collection of 2 iterators, nothing more.
External, non-intrusive, adaptation of a 3rd party type to make it model a particular concept that it doesn't model "inherently" is a fundamental generic programming maneuver. I don't see anything particularly wrong with making a pair of iterators model Range.
Jeremy Siek has described cases to me wherein one type can play two different roles with the *same* library. For that you need two different concept maps, to map the type into its different roles. Thus his recent "scoped concept_map" proposal.
Example please? The thing is, conceptually speaking, the pair has a very specific and well defined purpose (http://www.sgi.com/tech/stl/pair.html): ''' Pair<T1,T2> is a heterogeneous pair: it holds one object of type T1 and one of type T2. A pair is much like a Container, in that it "owns" its elements. It is not actually a model of Container, though, because it does not support the standard methods (such as iterators) for accessing the elements of a Container. ''' By "container", it's very clear that it models the tuple definition. It just so happens that STL does not have facilities for hetero-sequences. That is the domain of Fusion; and, as an STL extension, it fulfills that primary intent. It is also clear that the definition of pair does not, in any way, have anything to do with iterator ranges. I may grok what you say that there's no "wrong" here; it depends on the POV. However, if there is a conflict in definition such as in this case, it is my thinking that, for all intents and purposes, the definition that more closely follows the original intent, in the exact domain that it extends, has to take priority. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
All that being said, I don't care too much either way. It's not a concern of Fusion, AFAICT. Unless, you are asking for std::pair to be removed from the list of supported Fusion sequences?
Nope. Just raising the point for discussion.
Glad to hear :) Anyway... just one more before I go. I think I agree with you with there's no "wrong" here. But I'll add that there is definitely "better". And, I say, that the range definition of pair<T*,T*> is definitely *not* better. I'm not caring too much because we are all too accustomed to using a general representation for "something". We use int to specify all sorts of things and act on the data depending on the context. We supply ints as length arguments, as width, as age, etc. The same is happening with pair. It is used to specify different sorts of data. It so happens that in the case of Boost.Range, it is used to specify iterator_ranges. That's fine. But, we all know that that is error prone. We have come a long way. We've designed libraries like Quan to help in avoiding mis-representations of general types like int. Your "Dimensional Analysis" article discusses the very reasons why "numbers being manipulated don't stand alone". I'd say that the very essence of your article also applies to generic data types like pair. While this works: typedef pair<int, int> point; This is definitely better: struct point { /*...*/ pair<int, int> coords; }; The latter prevents you from shooting yourself in the foot by making sure that you are really dealing with points and not some other pair of ints that structurally looks like a point (i.e. has 2 ints). Having a pair of 2 ints alone does not constitute a point. Well, it can, but I can't say that a design, using such an approach, is good. IOTW, pair<T*,T*> used as an iterator_range loses one important aspect inherent in good design: type checking. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Guys, On Sep 29, 2006, at 10:25 AM, David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
To me it's like, generalizing that something with a wing, a propeller, and all things that comprise an airplane-- is an airplane. No, not necessarily. The presence of these elements do not complete the picture. It can be, say, *just a collection of parts*. Hence, pair<iterator,iterator> is just a collection of 2 iterators, nothing more.
External, non-intrusive, adaptation of a 3rd party type to make it model a particular concept that it doesn't model "inherently" is a fundamental generic programming maneuver. I don't see anything particularly wrong with making a pair of iterators model Range.
Yes. I also agree with Joel's position on airplanes (I misunderstood what he was saying at first... but yes, a pile of airplane parts is not an airplane), which is why I've always been in favor of explicit concept conformance. I see the concept_map declaration as the final touch that turns the parts into an airplane.
Jeremy Siek has described cases to me wherein one type can play two different roles with the *same* library. For that you need two different concept maps, to map the type into its different roles. Thus his recent "scoped concept_map" proposal.
Think of a variant of the accumulate function that instead of having parameters for an initial object and function object, requires the value_type of the iterators to be a model of Monoid... which just requires a binary operator and an initial object that is an identity with respect to the binary operator. The type "int" could model Monoid many ways. For example, it could use "+" for the binary operator and "0" for the initial object. It could also use "*" for the binary operator and "1" for the initial object.
All that being said, I don't care too much either way. It's not a concern of Fusion, AFAICT. Unless, you are asking for std::pair to be removed from the list of supported Fusion sequences?
Nope. Just raising the point for discussion.
I think the main thing to take away from this is that scoped concept maps are good. They allow you to have it both ways, in different parts of your program. And yes, we could solve the problem by requiring wrappers, but wrapping stuff is a pain. Cheers, Jeremy __________________________________ Jeremy Siek <siek@cs.colorado.edu> http://www.cs.colorado.edu/~siek/ Visiting Assistant Professor Department of Computer Science University of Colorado at Boulder

Jeremy Siek wrote:
Hi Guys,
Hi!
I think the main thing to take away from this is that scoped concept maps are good. They allow you to have it both ways, in different parts of your program.
And yes, we could solve the problem by requiring wrappers, but wrapping stuff is a pain.
I'd like to know more about scoped concept maps and how it can help in this scenario. Any pointers? Links? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Joel, On Sep 30, 2006, at 10:31 PM, Joel de Guzman wrote:
I'd like to know more about scoped concept maps and how it can help in this scenario. Any pointers? Links?
Here's the URL for the paper. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2098.pdf Cheers, Jeremy __________________________________ Jeremy Siek <siek@cs.colorado.edu> http://www.cs.colorado.edu/~siek/ Visiting Assistant Professor Department of Computer Science University of Colorado at Boulder

Jeremy Siek <jeremy.siek@gmail.com> writes:
I also agree with Joel's position on airplanes (I misunderstood what he was saying at first... but yes, a pile of airplane parts is not an airplane), which is why I've always been in favor of explicit concept conformance. I see the concept_map declaration as the final touch that turns the parts into an airplane.
That isn't even enough in this case. One pair<int*,int*> object is just a couple of pointers, while another is a sequence of ints. Scoped concept_maps get us closer, but I'm not sure it's fully general: you could still have both kinds of pair in the same code, right?
I think the main thing to take away from this is that scoped concept maps are good. They allow you to have it both ways, in different parts of your program.
And yes, we could solve the problem by requiring wrappers, but wrapping stuff is a pain.
Yep. There's too much of it already in C++. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Oct 1, 2006, at 6:17 AM, David Abrahams wrote:
Jeremy Siek <jeremy.siek@gmail.com> writes:
I also agree with Joel's position on airplanes (I misunderstood what he was saying at first... but yes, a pile of airplane parts is not an airplane), which is why I've always been in favor of explicit concept conformance. I see the concept_map declaration as the final touch that turns the parts into an airplane.
That isn't even enough in this case. One pair<int*,int*> object is just a couple of pointers, while another is a sequence of ints. Scoped concept_maps get us closer, but I'm not sure it's fully general: you could still have both kinds of pair in the same code, right?
Not sure exactly what you're saying... perhaps the following makes it more clear. With scoped maps, you can have different concept maps in scope in different parts of your code. So if you're about to call an algorithm, and you want pair<int*,int*> to be treated a something with just 2 elements, you would import the concept map from fusion. Later on, in a different scope, if you want pair<int*,int*> to be treated as something with second-first elements, then you'd import the concept map from the range library. Cheers, Jeremy __________________________________ Jeremy Siek <siek@cs.colorado.edu> http://www.cs.colorado.edu/~siek/ Visiting Assistant Professor Department of Computer Science University of Colorado at Boulder

Jeremy Siek <jeremy.siek@gmail.com> writes:
With scoped maps, you can have different concept maps in scope in different parts of your code.
So if you're about to call an algorithm, and you want pair<int*,int*> to be treated a something with just 2 elements, you would import the concept map from fusion.
Later on, in a different scope, if you want pair<int*,int*> to be treated as something with second-first elements, then you'd import the concept map from the range library.
Sure. So, leaving aside that I have the syntax and probably a few other things wrong: template <class T, Sequence<int*> S1, Sequence<T> S2, UnaryFunction<T,int*> F> void transform(S1 const& src, S2& dst, F f) { ... } struct address { template <class T> T* operator()(T& x) { return &x; } }; typedef std::pair<int*,int*> r; template <Sequence<int> S1> std::pair<int*,int*> f(S1 s) { r ret; // treat pair<int*,int*> as a sequence of int* concept_map<r, Sequence<int*> > { ... }; transform(s, ret, address()); } int storage[2]; r input = { storage, storage+2 }; // Treat pair<int*,int*> as a sequence of int concept_map<r, Sequence<int> > { ... }; // OK? r x = f(input); // which concept does x model? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Hi Dave, On Oct 2, 2006, at 4:40 AM, David Abrahams wrote:
Sure. So, leaving aside that I have the syntax and probably a few other things wrong:
template <class T, Sequence<int*> S1, Sequence<T> S2, UnaryFunction<T,int*> F> void transform(S1 const& src, S2& dst, F f)
typedef std::pair<int*,int*> r;
template <Sequence<int> S1> std::pair<int*,int*> f(S1 s) { r ret;
// treat pair<int*,int*> as a sequence of int* concept_map<r, Sequence<int*> > { ... };
transform(s, ret, address()); }
int storage[2]; r input = { storage, storage+2 };
// Treat pair<int*,int*> as a sequence of int concept_map<r, Sequence<int> > { ... };
// OK? r x = f(input);
// which concept does x model?
It's early in the morning, but I'll do my best... In this outer scope, the type 'r' models Sequence<int>, so the call to f type checks. Inside of function f, 'S1' models Sequence<int> and 'r' models Sequence<int*>. The call to transform will not type check because the requirement Sequence<int*> S1 is not satisfied. Cheers, Jeremy __________________________________ Jeremy Siek <siek@cs.colorado.edu> http://www.cs.colorado.edu/~siek/ Visiting Assistant Professor Department of Computer Science University of Colorado at Boulder

Jeremy Siek <jeremy.siek@gmail.com> writes:
It's early in the morning, but I'll do my best...
In this outer scope, the type 'r' models Sequence<int>, so the call to f type checks.
Inside of function f, 'S1' models Sequence<int> and 'r' models Sequence<int*>.
Cool, that's the key thing. Now, it's great that you can get there by using two scopes. You could imagine wanting to do the same thing from within a single function, but I don't think that's so easy.
The call to transform will not type check because the requirement Sequence<int*> S1 is not satisfied.
Because I got the requirements on transform backwards. Shoulda been: template <class T, Sequence<T> S2, Sequence<T*> S1, UnaryFunction<T,T*> F> void transform(S1 const& src, S2& dst, F f) I fear we're OT for Boost, now, though. Maybe we should take this private. -- Dave Abrahams Boost Consulting www.boost-consulting.com

----Original Message---- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman Sent: 29 September 2006 00:25 To: boost@lists.boost.org Subject: Re: [boost] [fusion] Support for classic boost::tuple
David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Joel de Guzman <joel@boost-consulting.com> writes:
Hi,
Ok, as promised. Support for classic boost::tuple has been added. Now yer ole boost tuples are full fusion citizens. Now boost::tuple can do for_each, transform, fold, find, assign/convert to other fusion sequences, etc.
Now there are 3 adapted sequences: 1) std::pair This one is going to cause me issues. I'm writing a unified library to operate on static and dynamic sequences. Here's the issue: is
pair<int*,int*>
a dynamic sequence that goes from the first pointer to the 2nd (as in Boost.Range), or a static sequence with 2 elements (a la Fusion)? Both? I think, in as much as boost::array<int> is a dynamic sequence that STL algorithms can operate on, and at the same time, is also a static sequence fusion algorithms can handle,
David Abrahams wrote: the same should be true for mono-sequences like pair<int*,int*>.
[what's a mono-sequence?]
The opposite of hetero-sequence :P
It's not the same thing at all. In the case of array<int>, the sequence has the same elements in either case; we're just talking about two ways of accessing the same sequence. In the case of std::pair there are two completely distinct interpretations, either of which could be valid. In my case I think there are only two possible choices:
1. say that std::pair needs to be wrapped or otherwise transformed before I know how to treat it.
2. pick one of the two interpretations.
I'm sorry. I think I'm lost. With:
pair<int*,int*>
or
tuple<int*,int*,int*,int*>
or
array<int*>
I see the same elements. What am I missing?
Cheers,
I think the problem is, should pair<int*,int*> a_pair_of_pointers; be treated the same as int* two_pointers[2]; or the same as int an_array_of_ints[ pair.second-pair.first ] The first is the obvious answer if you treat the pair as a special form of tuple. The second is the obvious answer is you consider the pair as two iterators over a sequence (like the Boost Range library). -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 203894

Oops. I see Dave has already explained it much more clearly than I have. Sorry for the noise. ----Original Message----
I think the problem is, should pair<int*,int*> a_pair_of_pointers;
be treated the same as int* two_pointers[2]; or the same as int an_array_of_ints[ pair.second-pair.first ]
The first is the obvious answer if you treat the pair as a special form of tuple. The second is the obvious answer is you consider the pair as two iterators over a sequence (like the Boost Range library).
-- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 203894
participants (7)
-
David Abrahams
-
Eric Niebler
-
Geoffrey Irving
-
Jeremy Siek
-
Joel de Guzman
-
Martin Bonner
-
Peter Dimov