
"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
using the library primitives inside the "apply" function. After all, why not make "apply" a free function?
template <class Params> void apply(Params& p, Whatever x) { // use p's "passive" interface to operate on x }
This looks like good idea, but as it is you couldn't put it into library, since you don't know which interface to use to operate on x.
That's been my point all along. No matter how you arrange things, the apply function can't go in the library. AFAICT, our submission gives you all the tools a library could give to make writing such a function possible. What more could you want?
What you could do is to make above function to apply all params to x
template <class Params> void apply(Params& p, Whatever x) { for_each<Param>( do_apply_to(x) ); }
and user will be required to write do_apply functions:
void do_apply( name_param, A& a ) { a.m_name = name_param.value; }
void do_apply( suffix_param, A& a ) { a.m_name.append( name_param.value ); }
void do_apply( prefix_param, A& a ) { a.m_name.prepend( name_param.value ); }
You really want to write three overloads rather than a single apply function? It doesn't seem like a win to me.
Hmm. Well, I did not find it nor in docs. Why IMO it's most important part of functionality. I see it now in test. Why did you name function f_list? Why not just f as rest of them?
Where are you seeing f_list?
In your test program.
I honestly don't know why, but my guess is that it's named that way to distinguish that it expects a named parameter bundle instead of individual parameters.
I meant "within brackets". My problem is that it's p[name | "abc"] while I would prefer something like p[name] | "abc".
That's not doable in general. Suppose the argument was an int? What is
p[index] | 3
??
Yeah,. I understand.it's not possible. But within brackets is not very good either IMO
Opinion noted.
It could. I did that.
Please show how the library can help with the "active" part. The passive library can be used to build an active component easily enough. I just don't see how the library can help with the apply call.
Yes. User will be required to implement all apply calls for all parameters. Note though:
1. "Passive" solution does require the same: one need to 'apply' (assign) named parameter value to the target at the point of usage (not in the library)
What is this obsession with OO? You are assuming that there's a target. In the general case, you're wrapping functions.
2. In case of "active" solution you actually do it once and then could reuse it for many different functions
class Entry { };
class Logger { public: template<Params> log( msg, Params p ) { Entry e( msg ); p.apply_to( e );
e.flush(); }
template<Params> buffer( msg, Params p ) { m_entries.push_back( Entry( msg ) ); p.apply_to( m_entries.back() ); }
template<Params> buffer( multichunk_msg, Params p ) { m_entries.push_back( Entry( multichunk_msg ) ); p.apply_to( m_entries.back() ); }
vector<Entry> m_entries; };
As I've repeatedly said, I don't see any way that any library could help you to build an active solution more than our proposal does already.
Sorry. I still not sure I understand. Let me put it as following example:
template<typename T> void log( std::string prefix, std::string name, std::string separ, T const& v ) { std::cout << prefix << name << separ << v; }
template<typename Params> void log( Params const& p ) { log( p[prefix | "" ], p[name], p[separator | " = " ], p[value] ); }
Yeah. In this case keyword "value" couldn't be typed.
The light dawns?
Ok. I slightly reworked my code see attached. Now it supports both typed and non-typed keywords. all in 120 lines (I am sure it could be made smaller by more effective mpl use). I also eliminated "keyword coupling". Now it should be as good in this regard as submitted library.
It's still not as good because you don't provide for overload restriction via SFINAE.
This library instead invented special mechanism of imposing restrictions.
Not really; it used a de-facto standard approach for passing compile-time functions.
Yeah. But in C++ de-facto standard approach for enforcing parameters types is to specify one.
Unless you're writing a function template.
If you have named template parameter it should be non-typed.
I guess you're not aware of the problems of overly-general function templates. Suppose you want to use a named parameter interface for this overload set? template <class T> void f(T*); template <class T> void f(boost::shared_ptr<T>&); Suppose you want to allow users to add new overloads, say for my_ptr<U>?
In other case it should be typed.
I do not know about python, but in c++ I prefer named interface wouldn't break by switching order of parameter specification.
What do you mean by "break?" When parameter names are used there is no restriction on parameter order.
f(arg1, arg2, arg3, key5 = arg5, key6 = arg6, key4 = arg4) ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positional position-independent.
Let consider an example of two optional parameters name, value. Then
foo( "abc", value = 5 ) works foo( value = 5 ) works foo( value = 5, "abc" ) doesn't work.
As it should be. Named parameters must always follow positional parameters. It's an easy rule to explain, and nobody gets confused.
These two are related; it should be clear from what I've written above. Your code can allow at most one of these (I didn't check): either it allows unchecked types and there's no ability to control overload resolution, or it doesn't support function templates with keyword arguments. And unless you have some way to induce SFINAE, you have no way to distinguish multiple overloads of the same function name accepting different named parameter sets:
int foo1( c_str name, float v, int i ) { }
int foo2( int id )
But you sad "multiple overloads of the same function" Above should look like int foo1( int id )
It doesn't matter one whit. I just used the names foo1 and foo2 for clarity. Change them both to food if you like!
{ }
template<class Params> int foo(Params const& params) { foo1( params[name], params[value], params[index] ); }
template<class Params> int foo(Params const& params) // error, foo already defined. { foo2( params[id] ); }
We don't need two. I would write:
template<class Params> int foo(Params const& params) { if( name and value present ) foo1( params[name], params[value], params[index] ); else foo1( params[index] ); }
No you can't. The two branches may not compile in the same instantiation. If no value was supplied and there's no default, accessing params[value] should be a compiler error. Plus, now you have an intrusive solution. A major reason to use overloading is that you *don't* have to modify an existing function to add an overload.
Yes. You can't develop keywords independently.
I do not see to many differences from your solution. You also need unique id for the keyword, which you then organize in ordered structure. So essentially getting the same result.
A unique name is much easier to come up with than a unique number. With numbers all the keywords need to coordinate.
Yeah, but you don't need PS to cause ETI and other issues on VC <= 7.0
Do we still care? Enough to affect the design/implementation?
Somebody cares.
I wouldn't be using it. Why would I use canon to kill sparrow.
Why would anyone kill a sparrow?!! ;-)
It's just Russian saying I was trying to translate.
I was only kidding. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com