
From: FlSt@gmx.de
You can find a new version of my class to the sandbox file vault (flos_junction.zip). It implements some of the ideas from this
Don't include the editor swap files in your zip file, please.
discussion. But it's very inefficient, because it makes a lot of copies.
I don't plan to look at the implementation until we reach some conclusion as to desirable interface and behavior. For example, your junction base class template provides size(), is_empty(), values(), operator container_type(), be(), and operator bool(). I'm not sure all of those are appropriate. Indeed, your design requires the junction to contain the values over which it operates. Why not have it reference the values over which it operates? I think it would be better to create a view of a container that gives it the junction behavior. That avoids copying elements, though it does require having a separate container with the elements. (Actually, I can envision the possibility of constructing a junction in such a way that it creates, populates, and owns a container if you don't have one already. Then, you can adapt an existing container or create one on demand.) That approach obviates the limited container interface you have created via size(), is_empty(), etc. BTW, the bool conversion should, probably, use the safe bool idiom.
I don't like the implementation, but it works and has the semantic I
Let's discuss the semantics apart from code (other than usage snippets) for now.
visualized. Probaly I will need some help to make it more efficient.
I'll gladly help with that when the time comes.
I see junctions as a expressive way to write comparisons and aritmethic operations on lists and as a alternative to loops.
Let's discuss the use cases. That discussion will form the basis for later documentation, and will focus the design.
Furthermore I must note that Perls junctions are not limited to sets. Junctions are more general. They can be applied to any list and are a logical linkage between the elements of the list, which determines the result of a comparison. That's exactly what my class implements. There
You make a good point. Junctions are useful to adapt other containers that match some concepts. That makes them more general than they otherwise would be. We need to decide what those concepts are, though.
are now four classes: conjunction<T>, disjunction<T>, abjunction<T> and injunction<T>. Whereas T is a Container-Type. And the Functions all_of, any_of, one_of, none_of create instances of this classes from a
Ah, you liked my ideas, eh?
container. See the examples. There is a base class junction, becaus elsewise I don't know how to support all the operators and circumvent writing duplicate code (There are already a lot of macros ;-). Is there a better way?
I'm not worried about that right now. My idea is that the junctions are given a range over which to operate and evaluate to a Boolean when compared with a given value. Using a range (Boost.Range) means that whole containers, iterator pairs, and more can be used to specify the elements that comprise the data over which the junction operates. Now let's look at usage: if (x == any_of(values)) Here, any_of() creates a disjunction over the supplied values. The namespace scope equality operator taking a right hand argument of a disjunction is called with x as the left hand argument. That might trigger a call to a function on the disjunction that returns a Boolean, which the equality operator returns. template <typename T> bool operator ==(T const & lhs_i, disjunction<T> const & rhs_i) { // do work // return answer } Since a call like the above is the likely usage, you don't want to copy the elements into the junction. You just want their extent. Then, the equality operator (indirectly?) iterates the range to figure out the correct answer. A complication is when comparing two junctions: if (none_of(values1) == any_of(values2)) This requires the cooperation of two junctions, if we forward to the junctions to get the answer. I suspect the better design is for the equality operators to do all of the work. template <typename T> bool operator ==(injunction<T> const & lhs_i, disjunction<T> const & rhs_i) { // do work // return answer } The equality operators can be friends of the junction classes so that they can iterate the elements. Just knowing which combination of types are used for the equality is sufficient to invoke the correct algorithm. So, for my first example, the equality operator would iterate the values looking for one that equals x. For my second example, the operator that expression invokes would iterate the values in values1 and check each one against all of the values in values2. Indeed, I see reuse there: for each element in values1, it degenerates to the first example. What do you think of this approach? Boost.Range gives us a wide range of types over which to operate, and putting the logic in the equality operators rather than the junction types gives us compile-time logic selection. The junction types merely serve as selectors for the appropriate equality operator. When I was writing the above, I had in mind that any_of() was a function template that created a disjunction. However, the class template could be called any_of. That way, "any_of(...)" is a constructor call; its use in the examples above creates temporary instances on which the equality operator can be invoked. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;