Re: Default argument for templatized function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Yeah, ok.  I really do know what I'm talking about with C++, I just
haven't
been able to get it to do what I want :P.  And I figured it was
something
like that (with respect to interpreting...), but why would it work so
easily
for the other case? (and yes just calling with the two parameters works
just
fine...)

I definitely know MANY ways to get around it, but it still makes generic
programming WAY more of a pain in the ass if you can't let it figure
things
like that out for itself.

Without the functionality of deriving the template for a default
argument,
which seems pretty straight forward to me by the way, it makes that a
fairly
gross limitation of gcc (lack of function specialization AND lack of
ability
to intuit from a default parameter).  I know there could be some issues
depending on the order the compiler goes through the steps, but man...
it
doesn't seem that complicated (I don't have any specific reference in
Bjarne
or anything...).

So should I submit this as a bug then?  It seems like the compiler
should be
able to do that (since it can't do def. template arguments for
functions).
Of course if they add default template arguments for functions... then
it
would be fine.  Suggestions?

Adruab

On Wed, 2004-05-12 at 01:32, Jonathan Wakely wrote:
> On Tue, May 11, 2004 at 03:44:35PM -0700, Adrian Bentley wrote:
> 
> > Ok so here's my problem, I have this templatized class (with T).  And
> > for it I'm defining a templatized member function (with F), I want the
> > function to take a comparison operation as a member to make it more
> > flexible.
> > 
> > I'm defining:
> > 
> > template < typename T >
> > class myclass
> > {
> > public:
> >         template < typename F >
> >         bool valid(const F & func = std::less<T>()) const
> >         {
> >                 //... use func as a binary function ...
> >         }
> > };
> > 
> > then in my cpp file else where (the instance is using T = float), I'm
> > calling:
> > 
> > myclass_inst.valid()
> > 
> > and I get this error:
> > 
> > 2465: no matching function for call to
> > `mynamespace::myclass<float>::valid()'
> 
> This is a C++ question, not specific to GCC, but I think what's going on
> is ...
> 
> Because there are no arguments to myclass<T>::valid<F>() the compiler
> can't do parameter deduction to work out what F should be, so it doesn't
> know which valid<F> you mean, and so it doesn't get as far as checking
> the argument list and using the default std::less<float>().
> (The name-lookup for valid<F> happens before the argument checking)
> 
> I think what you want is something like this (but this is illegal):
> 
>     template < typename F = std::less<T> >    // not legal
>         bool valid(const F & func = F()) const
>         {
>                 //... use func as a binary function ...
>         }
> 
> This says that by default type F is std::less<T>, and default constructs
> an F() if no argument is given. However, you're not allowed default
> template parameters on template functions, so this won't work. See
> below for a solution.
> 
> > It is bizarre because I'm defining a non-member function below like so:
> > 
> > template < typename T, typename F >
> > void operation(const myclass<T> &r1, const myclass<T> &r2, const F &
> > func = std::less<T>())
> > {
> >         //... compare stuff ...
> > }
> > 
> > and it works just fine!!!!!!  
> 
> Even when you call it as "operation(myclass_inst1, myclass_inst2)" ?
> The parameter deduction should fail here too.
> 
> > Not only that, but if I manually pass that comparison functor in the
> > call it works just fine:
> > 
> > myclass_inst.valid(std::less<float>())
> 
> Here you say you want to use valid<F> with F = std::less<float> so the
> name-lookup works, and the compiler then moves on to checking the 
> function arguments, and using a default constructed std::less<T>().
> 
> If you define the member function like this:
> 
>     template < typename F >
>         bool valid(const F & func = F()) const
>         {
>             // ...
>         }
> 
> You can call it like this:
> 
>     myclass_inst.valid<std::less<float> >();
> 
> But this is a bit verbose: it needlessly duplicates the fact that T=float,
> and passing the (default) argument to valid<F>() is redundant if the type
> is known. You might prefer this, using a template template parameter and
> simply instantiating the functor in the function body rather than taking
> an argument:
> 
>     template < template <typename> class F >
>         bool valid() const
>         {
>             F<T> f;    // just instantiate F here
>             // use f ...
>         }
> now:
>     myclass_inst.valid<std::less>();
> 
> (N.B. this only works for functors that take one template parameter,
> if that's a problem don't use the template template version)
> 
> 
> Finally, to make the functor default to std::less, I'd forget templates
> for a moment and overload valid() with a non-template member function:
> 
>     bool valid() const { return valid<std::less>(); }
> 
> Now myclass<T>.valid() uses std::less<T> , and if you want to use a
> different type you use the template function and explicitly name the
> type:
> 
>     assert( myclass_inst.valid() == myclass_inst.valid<std::less>() );
> 
> 
> I think your problem was trying to make one function too flexible and
> trying to do everything in one place. Seperate the concerns of the
> function template and the default type and it becomes easier.
> 
> jon
> 


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux