Boost logo

Boost :

From: Gennadiy Rozental (gennadiy.rozental_at_[hidden])
Date: 2004-11-16 21:39:38


> >> 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.

1. What if both prefix and suffix above are optional. How would you
implement above apply
2. What if I do not know about all possible grist to the name? What if I
want to allow users to be able to extend set of possible "grists". In my
proposition one could define own keyword and implement do_apply and that's
it.

> >> > 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.

It's not an obsession. As I mention in my original post, in my experience I
found most need in named parameter interface in constructors for some
complex classes. There you have 'natural' target: this In case of functions
passive solutions does look more attractive. Though in some cases (like one
I disrobed above) I would still employ passive one.

> > 2. In case of "active" solution you actually do it once and then
> > could reuse it for many different functions

> 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.

Traversing apply would help.

> > 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.

> > 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>?

Following example works with my code:

////////////////////////////////////////////////////////////////
// Example:

#include <iostream>
#include <boost/shared_ptr.hpp>

namespace test
{
  keyword<struct instance_t> instance;

  template<typename T>
  void foo_impl( T* t )
  {
      std::cout << "non shared " << *t << std::endl;
  }

  template<typename T>
  void foo_impl( boost::shared_ptr<T> t )
  {
      std::cout << "shared " << *t << std::endl;
  }

  template<class Params>
  void foo(Params const& params)
  {
      foo_impl( params[instance] );
  }
}

int main()
{
   using test::foo;
   using test::instance;

   int i = 5;

   foo( instance = &i );
   foo( instance = boost::shared_ptr<float>( new float(1.2) ) );

   return 0;
}

> > 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.

Does it gets explained anywhere in docs?

> >> template<class Params>
> >> int foo(Params const& params)
> >> {
> >> food( params[name], params[value], params[index] );
> >> }
> >>
> >> template<class Params>
> >> int foo(Params const& params) // error, foo already defined.
> >> {
> >> food( 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.

It was pseudocode. It's a compile time if:

if_<cond,invoke1,invoke2>::type::invoke( params );

> 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.

Could you show in more details example for this case (including how you
library solve the problem), then I could better comment it.

> >> 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.

You also need to coordinate by combining all keyword designators into
keywords structure. Though I agree that types are better (not significantly,
would it cost to use types instead of numbers I would prefer numbers)

> Dave Abrahams

Gennadiy.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk