
On 6/24/11 9:08 AM, Stewart, Robert wrote:
er wrote:
I am sure that it is a powerful library, but I really have no idea at all what is going on. I can't even parse the first line as valid C++ in any way. You need better examples, and also is that really the best way you could find to express repeating?
If I try to imagine what the interface would look like after taking into account some of the suggestions that were made, this sentence:
"Create data elements by mapping 1, 10, 100, 1000 by function f, and insert each result in cont by invoking modifier push_front."
If I interpret that correctly, it would be clearer as:
"Create elements in cont, using push_front(), by calling f() 1, 10, 100, and 1000 times."
Noted, thanks.
translates to
( push_front<1>( cont ) % ( _data = f ) % ( _repeat = n ) )( 1, 10, 100, 1000 );
Why the leading underscores on "_data" and "_repeat?"
It's part of a set of conventions that are pervasive throughout the library: trailing underscore for types, leading one for const objects: const name_ _name = {}; Names without underscores are reserved for functions.
Questions : - is it more readable, now? - What if each example was preceded by its English equivalent.
Preceding each by a clear English equivalent is necessary.
Noted.
Could that code be spelled like the following instead?
push_front<1>(cont).from(f).repeated(1, 10, 100, 1000);
That is, instead of operator overloading, member functions would make things clearer and more succinct. Is there more to the operator
overloading than I know making the member function approach too restrictive? What happens to your operator overloading approach when a To use a proverbial expression, the member function approach is "carved in stone", if you like. Not using operator%. I'm going to assume that 'object' is returned by put( cont ) or deque<T>( _nil ). It doesn't matter which, since they rely on the same implementation. Consider ( object % option1 % ... % optionn )(1, 10, 100, 1000); object has two (orthogonal) components : the data-generator, which maps arguments to a data-element, and the modifier which takes care of inserting that data-element. Each option modifies either of these two components. For example ( object % ( _data = f ) )( 1, 10, 100, 1000 ); changes the data-generator to f. For example, ( object % ( _repeat = n ) )( 1, 10, 100, 1000 ); wraps a new modifier around the one that already resides in object (say push_back), such as to invoke it n times. While this is perhaps not as intuitive as desired, it's in my view an irreducible price to pay to have modularity and open for extension : one can customize an option. I anticipated that this would be a problem and already provided some remedy (I won't delve on it), but did not push the reasoning far enough. The next step, I think, is to try to get back to functions, as you suggest, but free functions, not member functions. I already proposed a new syntax. Let me repeat it: push_front<1>( cont )( 1, 10, 100, 1000 ); would be equivalent to the less eye candy ( put<1>( cont ) % _push_front )( 1, 10, 100, 1000 ); Consequently, using the first form, the use of operator% would appear, only for additional options: ( push_front<1>( cont ) % ( _data = f ) % ( _repeat = n ) )( 1, 10, 100, 1000 ); One way to see that being able to encapsulate an option as an object is a good thing, however, is to imagine to have to write two unit tests: void unit_test1() { std::deque<T> v; v.push_back( T( args1... ) ); ...; v.push_back( T( argsn...) ) // whatever } void unit_test2() { std::deque<int> v; v.push_front( T( args1... ) ); ...; v.push_front( T( argsn...) ) // whatever } With V2, you can do the same like this: template<typename Option> void unit_test(Option option) { std::deque<int> vec; ( put( vec ) % option )( args1... )...( argsn... ); // whatever } unit_test( _push_back ); unit_test( _push_front ); Some people might find this contrived. Fair enough, but it's meant to make a point about modularity, which should have some benefit in less contrived situations. HTH, and thanks for your interest.