public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Default argument for templatized function
@ 2004-05-11 22:44 Adrian Bentley
  2004-05-12  8:32 ` Jonathan Wakely
  2004-05-13  1:03 ` llewelly
  0 siblings, 2 replies; 8+ messages in thread
From: Adrian Bentley @ 2004-05-11 22:44 UTC (permalink / raw)
  To: gcc-help

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 the only error I get (hence I am not including the rest of the
build messages), and I have not been able to resolve this.

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

Not only that, but if I manually pass that comparison functor in the
call it works just fine:

myclass_inst.valid(std::less<float>())


MY @!*$(@#*&$*.  I've tried putting typename everywhere around the
parameter value, typedefing for T, etc. nothing works.  It's crazy....  
I would be greatful for any clues.

Adruab


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-11 22:44 Default argument for templatized function Adrian Bentley
@ 2004-05-12  8:32 ` Jonathan Wakely
  2004-05-12 17:50   ` Adrian Bentley
  2004-05-13  1:03 ` llewelly
  1 sibling, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2004-05-12  8:32 UTC (permalink / raw)
  To: Adrian Bentley; +Cc: gcc-help

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


-- 
"The music business is a cruel and shallow money trench, a long
 plastic hallway where thieves and pimps run free, and good men die
 like dogs.  There's also a negative side."
	- Hunter S. Thompson

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-12  8:32 ` Jonathan Wakely
@ 2004-05-12 17:50   ` Adrian Bentley
  2004-05-13  1:10     ` llewelly
  2004-05-13  8:05     ` Jonathan Wakely
  0 siblings, 2 replies; 8+ messages in thread
From: Adrian Bentley @ 2004-05-12 17:50 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-help

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
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-11 22:44 Default argument for templatized function Adrian Bentley
  2004-05-12  8:32 ` Jonathan Wakely
@ 2004-05-13  1:03 ` llewelly
  1 sibling, 0 replies; 8+ messages in thread
From: llewelly @ 2004-05-13  1:03 UTC (permalink / raw)
  To: Adrian Bentley; +Cc: gcc-help

Adrian Bentley <adruab@voria.com> writes:

> 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
[snip]

14.8.2.4/17:

    # A template type-parameter cannot be deduced from the type of a
    # function default argument.

It then continues with an example much like yours.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-12 17:50   ` Adrian Bentley
@ 2004-05-13  1:10     ` llewelly
  2004-05-13  8:05     ` Jonathan Wakely
  1 sibling, 0 replies; 8+ messages in thread
From: llewelly @ 2004-05-13  1:10 UTC (permalink / raw)
  To: Adrian Bentley; +Cc: Jonathan Wakely, gcc-help

Adrian Bentley <adruab@voria.com> writes:
[snip]
> 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

It is not a limitation of gcc. It is a limitation of ISO C++ . See
    14.8.2.4/17 .

> (lack of function specialization

Function specialization works fine in gcc. Note ISO C++ does not allow
    *partial* specialization of function templates.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-12 17:50   ` Adrian Bentley
  2004-05-13  1:10     ` llewelly
@ 2004-05-13  8:05     ` Jonathan Wakely
  2004-05-13 21:46       ` Adrian Bentley
  1 sibling, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2004-05-13  8:05 UTC (permalink / raw)
  To: Adrian Bentley; +Cc: gcc-help

On Wed, May 12, 2004 at 10:49:51AM -0700, Adrian Bentley wrote:

> 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 can't get the code you posted (incomplete as it was) to compile with
GCC 2.95, 3.3, 3.4, or with Comeau's compiler.

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

The solution I posted does what you want, with little extra code. Making
it do it your way would require a change to the language, which is
unnecessary since you can achieve the desired effect as I showed.

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

You never said which version of the compiler you had tried, but it doesn't
matter as GCC is right to reject the code you posted.

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

That's the rules of the language.  As llewelly said, see 14.8.2.4/17.

Calling a function template with no arguments and without explicitly
stating which specialisation you want means that the compiler cannot
deduce the parameters. This is not a limitation of GCC.

> Of course if they add default template arguments for functions... then
> it
> would be fine.  Suggestions?

You could submit a proposal for a language change to the standards
committee (but don't hold your breath for it to be accepted).

jon

-- 
"The only cure for the ills of democracy is more democracy."
	- Al Smith

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-13  8:05     ` Jonathan Wakely
@ 2004-05-13 21:46       ` Adrian Bentley
  2004-05-13 21:48         ` Adrian Bentley
  0 siblings, 1 reply; 8+ messages in thread
From: Adrian Bentley @ 2004-05-13 21:46 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-help

Yeah, ok, fine, it's nice to see that no one else finds this
irritating.  I fixed it already, but it is a hack (generics are supposed
to be elegant...).

However, gcc still seems to be inconsistent.  The reason why the second
one worked, was that I had two functions (one with a 3rd argument and
one without).  Shouldn't it cause a warning or something if it's
ignoring a default argument like that, and there's a second function
with the exact same first two?  I mean sure it can all be chalked up to
template weirdness, but sheesh.

In the end these are all just work arounds for not being able to have
default template arguments for functions (which should have been fixed
long ago).  Standards are good, but it seems to be becoming more and
more inflexible, but perhaps that is just me being confused.

Thanks for the smackdown folks (slightly enlightening though it was),
I'll be sure to just fix what I've got in the future.

Adruab

On Thu, 2004-05-13 at 01:05, Jonathan Wakely wrote:
> On Wed, May 12, 2004 at 10:49:51AM -0700, Adrian Bentley wrote:
> 
> > 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 can't get the code you posted (incomplete as it was) to compile with
> GCC 2.95, 3.3, 3.4, or with Comeau's compiler.
> 
> > 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.
> 
> The solution I posted does what you want, with little extra code. Making
> it do it your way would require a change to the language, which is
> unnecessary since you can achieve the desired effect as I showed.
> 
> > 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...).
> 
> You never said which version of the compiler you had tried, but it doesn't
> matter as GCC is right to reject the code you posted.
> 
> > 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).
> 
> That's the rules of the language.  As llewelly said, see 14.8.2.4/17.
> 
> Calling a function template with no arguments and without explicitly
> stating which specialisation you want means that the compiler cannot
> deduce the parameters. This is not a limitation of GCC.
> 
> > Of course if they add default template arguments for functions... then
> > it
> > would be fine.  Suggestions?
> 
> You could submit a proposal for a language change to the standards
> committee (but don't hold your breath for it to be accepted).
> 
> jon

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Default argument for templatized function
  2004-05-13 21:46       ` Adrian Bentley
@ 2004-05-13 21:48         ` Adrian Bentley
  0 siblings, 0 replies; 8+ messages in thread
From: Adrian Bentley @ 2004-05-13 21:48 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-help

Ok to ammend that, I'm not trying to be hostile.  I'm really just
looking for sympathy :P, perhaps that would have been better found else
where.

Adruab
On Thu, 2004-05-13 at 14:46, Adrian Bentley wrote:
> Yeah, ok, fine, it's nice to see that no one else finds this
> irritating.  I fixed it already, but it is a hack (generics are supposed
> to be elegant...).
> 
> However, gcc still seems to be inconsistent.  The reason why the second
> one worked, was that I had two functions (one with a 3rd argument and
> one without).  Shouldn't it cause a warning or something if it's
> ignoring a default argument like that, and there's a second function
> with the exact same first two?  I mean sure it can all be chalked up to
> template weirdness, but sheesh.
> 
> In the end these are all just work arounds for not being able to have
> default template arguments for functions (which should have been fixed
> long ago).  Standards are good, but it seems to be becoming more and
> more inflexible, but perhaps that is just me being confused.
> 
> Thanks for the smackdown folks (slightly enlightening though it was),
> I'll be sure to just fix what I've got in the future.
> 
> Adruab
> 
> On Thu, 2004-05-13 at 01:05, Jonathan Wakely wrote:
> > On Wed, May 12, 2004 at 10:49:51AM -0700, Adrian Bentley wrote:
> > 
> > > 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 can't get the code you posted (incomplete as it was) to compile with
> > GCC 2.95, 3.3, 3.4, or with Comeau's compiler.
> > 
> > > 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.
> > 
> > The solution I posted does what you want, with little extra code. Making
> > it do it your way would require a change to the language, which is
> > unnecessary since you can achieve the desired effect as I showed.
> > 
> > > 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...).
> > 
> > You never said which version of the compiler you had tried, but it doesn't
> > matter as GCC is right to reject the code you posted.
> > 
> > > 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).
> > 
> > That's the rules of the language.  As llewelly said, see 14.8.2.4/17.
> > 
> > Calling a function template with no arguments and without explicitly
> > stating which specialisation you want means that the compiler cannot
> > deduce the parameters. This is not a limitation of GCC.
> > 
> > > Of course if they add default template arguments for functions... then
> > > it
> > > would be fine.  Suggestions?
> > 
> > You could submit a proposal for a language change to the standards
> > committee (but don't hold your breath for it to be accepted).
> > 
> > jon
> 
> 
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2004-05-13 21:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-11 22:44 Default argument for templatized function Adrian Bentley
2004-05-12  8:32 ` Jonathan Wakely
2004-05-12 17:50   ` Adrian Bentley
2004-05-13  1:10     ` llewelly
2004-05-13  8:05     ` Jonathan Wakely
2004-05-13 21:46       ` Adrian Bentley
2004-05-13 21:48         ` Adrian Bentley
2004-05-13  1:03 ` llewelly

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).