C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

template member trouble
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Buster
Guest





PostPosted: Tue Feb 14, 2006 6:06 pm    Post subject: template member trouble Reply with quote



g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template parameter, so a
declaration of 'func1' must be available

Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the
compiler, so I can't figure out what to change to
fix it. Any ideas ?

template <typename T>
class Foo
{
public:

void func1()
{
}
};

template <typename T>
class Bar: public Foo<T>
{
public:

void func2()
{
func1();
}
};

void func3()
{
Bar<int> p;

p.func2();
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kwikius
Guest





PostPosted: Wed Feb 15, 2006 2:06 pm    Post subject: Re: template member trouble Reply with quote



Buster wrote:
Quote:
g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template parameter, so a
declaration of 'func1' must be available

[...]

explicitly specify this-> func to delay lookup of func1 till Bar is
instantiated.

template <typename T>
class Bar: public Foo<T>
{
public:
void func2()
{
this->func1();
}
};

regards
Andy Little


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Thomas Maeder
Guest





PostPosted: Wed Feb 15, 2006 2:06 pm    Post subject: Re: template member trouble Reply with quote



Buster <booster (AT) retriever (DOT) dyndns.org> writes:

Quote:
In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template
parameter, so a declaration of 'func1' must be available

Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the
compiler, so I can't figure out what to change to
fix it. Any ideas ?

template <typename T
class Foo
{
public:

void func1()
{
}
};

template <typename T
class Bar: public Foo<T
{
public:

void func2()
{
func1();

Names in C++ templates are looked in two phases. Names that depend on
the template parameter are looked up when the template is instantiated
(once per instantiation). Other names are looked up when the template
is parsed (once per compilation).

The rationale is that if the lookup leads to an error, the compiler
output may be clearer if it is only produced once per compilation
rather than once for each instantiation.

func1 is not dependant, so it is looked up when the template is
parsed. At this time, names inherited from base class templates are
not considered, because a specialization of the base class template
may be defined later that does not declare a name from the base base
template (or that declares it to name something different than the
base base class template).

The solution is to make the name func1 dependant, e.g. by writing
either

this->func1();

or

Foo<T>::func1();

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Wed Feb 15, 2006 2:06 pm    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template parameter, so a
declaration of 'func1' must be available

That has to be one of the clearest and best worded error
messages I've seen in a long time.

Quote:
Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the compiler,

Not really, but to understand why not, you have to understand
the distinction between dependent and non-dependent name lookup.

The g++ error message makes it clear that non-dependent lookup
is being used (which is correct, according to the standard).

Quote:
so I can't figure out what to change to fix it. Any ideas ?

template <typename T
class Foo
{
public:

void func1()
{
}
};

template <typename T
class Bar: public Foo<T
{
public:

void func2()
{
func1();

Read the error message. There is nothing here which makes the
compiler use dependent lookup. So it uses non-dependant lookup.
Non-dependant lookup takes place in the context of the template
definition, independantly of any value for T. This means that
the compiler does not have available, and does not consider,
anything which depends on T -- in particular, it cannot consider
anything in Foo<T>, because it has no instantiation of Foo<T> to
look at. (Using the language of the standard, the base class
here is a dependent type, and does not participate in the lookup
of non-dependent names.)

The solution, obviously, is to make func1 dependent. There are
at least three ways to do so: passing it a parameter which has a
dependent type, adding a this-> (since this is always
dependent), or using a scope resolution operator Foo<T>::.
Since we probably don't want to change the signature in the base
class, this leaves us with:
this->func1() ;
or
Foo<T>::func1() ;

Once the expression is dependent, name lookup in it will be
deferred until instantiation. At which point Foo<T> will be
instantiated and known.

Quote:
}
};

void func3()
{
Bar<int> p;

p.func2();
}

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Sumit Rajan
Guest





PostPosted: Wed Feb 15, 2006 2:06 pm    Post subject: Re: template member trouble Reply with quote

"Buster" <booster (AT) retriever (DOT) dyndns.org> wrote in message
news:57nIf.1587$JR6.658 (AT) newsread3 (DOT) news.pas.earthlink.net...
Quote:
g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template
parameter, so a
declaration of 'func1' must be available

Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the
compiler, so I can't figure out what to change to
fix it. Any ideas ?

template <typename T
class Foo
{
public:

void func1()
{
}
};

template <typename T
class Bar: public Foo<T
{
public:

void func2()
{


Quote:
func1();
Try "this->func1();" or "Foo<T>::func1();" instead of the above.


Quote:
}
};

Please see:
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

Regards,
Sumit.
--
Sumit Rajan <sumitr (AT) msdc (DOT) hcltech.com>



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Thomas Tutone
Guest





PostPosted: Wed Feb 15, 2006 2:06 pm    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template parameter, so a
declaration of 'func1' must be available

Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the
compiler, so I can't figure out what to change to
fix it. Any ideas ?

template <typename T
class Foo
{
public:
void func1()
{
}
};

template <typename T
class Bar: public Foo<T
{
public:

void func2()
{
func1();

change the above line to either:

this->func1();

or:

Foo<T>::func1();

Best regards,

Tom


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Valentin.Samko
Guest





PostPosted: Wed Feb 15, 2006 6:06 pm    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
template <typename T
class Foo
{
void func1() {}
};

template <typename T
class Bar: public Foo<T
{
void func2() { func1(); }
};

void func3()
{
Bar<int> p;
p.func2();
}
This should not compile with a compiler which properly implements two

phase lookup. You need "void func2() { this->func1(); }" there, as
func1 is dependent on the template, and Foo<T> is not known until T is
known.

Valentin Samko


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Nicola Musatti
Guest





PostPosted: Wed Feb 15, 2006 6:06 pm    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
g++ is giving me a strange error when I compile the
attached code. It says:

In member function 'void Bar<T>::func2()':
error: there are no arguments to 'func1' that depend on a template parameter, so a
declaration of 'func1' must be available

Making either Foo or Bar non-template makes it work.

It looks to me like everything is available to the
compiler, so I can't figure out what to change to
fix it. Any ideas ?

See the forth bullet here:
http://gcc.gnu.org/gcc-3.4/changes.html#cplusplus

Cheers,
Nicola Musatti


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Buster
Guest





PostPosted: Thu Feb 16, 2006 3:06 am    Post subject: Re: template member trouble Reply with quote

Thomas Maeder wrote:
Quote:

Names in C++ templates are looked in two phases. Names that depend on
the template parameter are looked up when the template is instantiated
(once per instantiation). Other names are looked up when the template
is parsed (once per compilation).

The rationale is that if the lookup leads to an error, the compiler
output may be clearer if it is only produced once per compilation
rather than once for each instantiation.

I suspect that you're being gracious to the language designers.
My guess is that they wanted to give the compiler writers the
option to do the name look-up separate from the name resolution.
If a name were "committed" to dependent look-up, it would be "too
hard" to go back and send it down the deferred dependent look-up
path.

I think this was a bad choice. The compiler's job is to grok the
intent of the programmer. I'm not suggesting abolishing non vs
dependent look-up. I'm suggesting that the choice should be
implicitly made by the compiler. It makes so many others. It
seems a shame to let it off the hook for a case that knocks down
one of the pillars of OOP.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Sat Feb 18, 2006 1:06 am    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
Thomas Maeder wrote:

Names in C++ templates are looked in two phases. Names that
depend on the template parameter are looked up when the
template is instantiated (once per instantiation). Other
names are looked up when the template is parsed (once per
compilation).

The rationale is that if the lookup leads to an error, the
compiler output may be clearer if it is only produced once
per compilation rather than once for each instantiation.

I suspect that you're being gracious to the language
designers. My guess is that they wanted to give the compiler
writers the option to do the name look-up separate from the
name resolution. If a name were "committed" to dependent
look-up, it would be "too hard" to go back and send it down
the deferred dependent look-up path.

Are you kidding. You can say or think what you like about two
phased look-up, but one thing is certain -- it makes life a lot,
lot harder for compiler implementors. Why do you think it took
so long for compilers to implement it?

The "pre-standard" situation was simple for compiler writers:
just squirrel the tokens away, and do all of the binding at
instantiation time. With the possiblity, of course, that it
then finds a definition the template author hadn't considered,
or didn't want. (In practice, I never found this to be a real
problem. But in practice, of course, what we did with templates
was a lot simpler back then.)

Quote:
I think this was a bad choice. The compiler's job is to grok
the intent of the programmer. I'm not suggesting abolishing
non vs dependent look-up. I'm suggesting that the choice
should be implicitly made by the compiler. It makes so many
others. It seems a shame to let it off the hook for a case
that knocks down one of the pillars of OOP.

The problem *is* that the choice is implicitly made by the
compiler. According to a complex set of rules. And that it
isn't the compiler, who knows whether the name should come from
the global context, or from a context dependant on the
instantiation, but rather the author of the template.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Sat Feb 18, 2006 1:06 am    Post subject: Re: template member trouble Reply with quote

Thomas Maeder wrote:

[...]
Quote:
Names in C++ templates are looked in two phases. Names that
depend on the template parameter are looked up when the
template is instantiated (once per instantiation). Other names
are looked up when the template is parsed (once per
compilation).

The rationale is that if the lookup leads to an error, the
compiler output may be clearer if it is only produced once per
compilation rather than once for each instantiation.

I think the rationale is more that the error messages will be
clearer if they appear at the point of the template definition,
and not at some arbitrary point in user code where the template
is instantiated.

I think an even more important point of the rationale is to
prevent accidental name hijacking. Consider something like:

extern int f() ;

template< typename T >
struct S : T
{
int g() { return f() ; }
} ;

Now what happens if, by chance, T contains a member function
f()? The idea is that when I write the template, I know whether
I want the global function f(), or a member function f(); more
generally, for each symbol, I know whether I want it bound once
and for all, regardless of the instantiation, or whether I want
the bounding to depend on the instantiation. And I specify
which.

The problem I have with the current situation is that I don't
specify which. The compiler decides whether the name is
dependant or not based on a fairly complex and obscure set of
rules, and I have to play games with my code to trick it into
using the one I want. Which can lead to some pretty obscure
problems.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Allan W
Guest





PostPosted: Sat Feb 18, 2006 1:06 am    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
I think this was a bad choice. The compiler's job is to grok the
intent of the programmer. I'm not suggesting abolishing non vs
dependent look-up. I'm suggesting that the choice should be
implicitly made by the compiler. It makes so many others. It
seems a shame to let it off the hook for a case that knocks down
one of the pillars of OOP.

Wow! Possibly a little overstated?

Which one of the "pillars of OOP" got knocked down?

I'm trying to picture the press release where industry giants
discuss why object-oriented programming failed. "It was doing
pretty good," someone suggests, "but then the C++ standards
committee decided that some compilers might want to do
2-phase lookup on function templates. The pillars began to
tumble, and now in 2006 almost all experts agree that the very
concept of OOP has failed... and it's C++'s fault."

Is this the picture you intended? If so, why?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Buster
Guest





PostPosted: Tue Feb 21, 2006 12:06 am    Post subject: Re: template member trouble Reply with quote

kanze wrote:
Quote:

Now what happens if, by chance, T contains a member function f() ?

You have that today. Add a global "void func1();" anywhere above
Bar and you have a silent error. Either way you do it, someone's
going to get it wrong.

Quote:
The problem I have with the current situation is that I don't
specify which. The compiler decides whether the name is
dependant or not based on a fairly complex and obscure set of
rules, and I have to play games with my code to trick it into
using the one I want. Which can lead to some pretty obscure
problems.

The problem I have is that the rules seem to have moved against
the OO programmer. Now s/he to explicitly qualify base
function calls, where before it was the global function caller
who had to be explicit. The industry isn't shifting back to
global functions, is it ?

Now, if I templatize a class (hierarchy), even to so much as
strategize with respect to, e.g. allocation or synchronization,
I have to run through it with a different set of rules and make
sure it will call the correct function.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Tue Feb 21, 2006 11:06 am    Post subject: Re: template member trouble Reply with quote

Buster wrote:
Quote:
kanze wrote:

Now what happens if, by chance, T contains a member function
f() ?

You have that today. Add a global "void func1();" anywhere
above Bar and you have a silent error. Either way you do it,
someone's going to get it wrong.

I'm not sure of the entire context here. Nor, for that matter,
what you mean by "today" -- there's still some variation between
compilers.

With regards to the standard, on the other hand, the issue is
clear: there are two types of look-up. If the symbol is not
dependent, look-up occurs when the template is defined, and the
symbol is definitively bound at that time. If the results are
different between two different translation units, you have
undefined behavior -- I believe that some compilers actually
catch this and generate an error. If the symbol is dependent,
name look-up takes place on instantiation, in two contexts: that
of the point of instantiation, and that of the definition of the
template (although in the latter context, only argument
dependent name lookup is used).

If my template contains a line:
func1() ;
then non dependent name look-up is used -- this will find a
member function in a non-dependent base class, or a function at
namespace scope in all enclosing namespaces. It will not find a
function in a dependent base class, for the simple reason that
the compiler cannot know, at this point, what functions the
dependent base class contains.

If there is no declaration of func1(), it is an error. There
must be such a declaration. So I don't see how adding such a
declaration could create a silent error.

If you modify the expression to make the name dependent, e.g.:
this->func1() ;
then a global function will not be found.

You can get unexpected results, of course. If the function call
is something like "func1( T() )", with a dependent type as
parameter, the compiler will look in the (dependent and
non-dependent) base classes -- if it doesn't find the function
there, it will look for a global function. Depending on the
contents of the dependent base classes, it's quite possible that
some instantiations use a member function of the base class, and
others a free function declared at namespace scope. I believe
that this is intentional -- the desired behavior, and not an
accidental side effect.

I'd be interested in seeing an example of where you see the
silent error, however.

Quote:
The problem I have with the current situation is that I
don't specify which. The compiler decides whether the name
is dependant or not based on a fairly complex and obscure
set of rules, and I have to play games with my code to trick
it into using the one I want. Which can lead to some pretty
obscure problems.

The problem I have is that the rules seem to have moved
against the OO programmer.

I don't think that there is any pro or contra vis-a-vis the OO
programmer here.

Quote:
Now s/he to explicitly qualify base function calls, where
before it was the global function caller who had to be
explicit. The industry isn't shifting back to global
functions, is it ?

In some cases:-). But I don't think that this is an example of
it. The problem here is that you need to tell the compiler that
the function is dependent. And it happens to fall out of the
rules that one way of doing this is by prefixing it with this->.
There is no intent that it be necessary to explicitly qualify
base function calls, and most of the time it isn't; it's only
necessary IF the base class is a dependent type, *and* there are
no dependent arguments or other things which would make the call
dependent.

In general, in template code, even before the current rules, the
safest policy was always to qualify everything to a maximum --
to avoid possible accidental name hijacking. So in theory, at
least, for a maximum robustness, you would have written
this->f() if you wanted the base class function, and ::f() if
you wanted a global function. (I say in theory, because in
practice, I've never encountered a case of name hijacking, even
when no precautions were taken. Large projects use naming
conventions, especially for anything in global scope, and so a
global function and a member function never have the same name
anyway.)

Quote:
Now, if I templatize a class (hierarchy), even to so much as
strategize with respect to, e.g. allocation or
synchronization, I have to run through it with a different set
of rules and make sure it will call the correct function.

That's always been the case. The difference now is that
typically, if you expected to use the base class function, you
will get a compiler error in the template definition, rather
than in the instantiation. Unless, of course, you have a global
function with the same name -- in that case, your code will
silently behave differently, depending on the compiler you are
using.

Once export becomes more widespread, of course, the problem will
disappear. Because you'll include the header with the template
as the first header in the implementation sources, and compile
it there, where you are sure that there are no extra, unwanted
global function declarations. If you want a base class member,
and forget the this->, you will get an error, independantly of
whatever other headers your client code may include before
yours.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Buster
Guest





PostPosted: Wed Feb 22, 2006 9:06 pm    Post subject: Re: template member trouble Reply with quote

kanze wrote:
Quote:

I'm not sure of the entire context here. Nor, for that matter,
what you mean by "today" -- there's still some variation between
compilers.

I presume any compiler adhering to the current standard would
give me the error I experienced ? I use g++ 4.0.

Quote:
I'd be interested in seeing an example of where you see the
silent error, however.

I was replying to your comment about 'name hijacking'. The new
rules are vulnerable to it also. By adding the declaration
I mentioned, the global func1() would be called and the OO
programmer who intended to call the inheritted func1() wouldn't
find out until run-time. 'silent', meaning no compiler warning or
error; 'error', meaning not what the programmer intended and
likely to crash.

So my point was: no matter which way you go, someone will
experience unexpected results. So why not choose the path
that is consistent with non-template inheritance rules ?

Quote:
I don't think that there is any pro or contra vis-a-vis the OO
programmer here.

There is, in that I didn't used to have to put this-> in
front of calls that were inheritted. I feel like a Python
programmer, putting self. in front of everything.

Quote:
In general, in template code, even before the current rules, the
safest policy was always to qualify everything to a maximum --
to avoid possible accidental name hijacking. So in theory, at
least, for a maximum robustness, you would have written
this->f() if you wanted the base class function, and ::f() if
you wanted a global function. (I say in theory, because in
practice, I've never encountered a case of name hijacking, even
when no precautions were taken. Large projects use naming
conventions, especially for anything in global scope, and so a
global function and a member function never have the same name
anyway.)

Just as you say, I never qualified anything and never ran into
any trouble. If I ever did, I would much prefer qualifying a
call to a global function than a member function, since I
make so few that have a chance of colliding.

Quote:
Now, if I templatize a class (hierarchy), even to so much as
strategize with respect to, e.g. allocation or
synchronization, I have to run through it with a different set
of rules and make sure it will call the correct function.

That's always been the case.

No, it isn't. The standard used to favor inheritance, and if
I templatized a class, it worked just fine. e.g. Even the
hijacking version of my example works as expected on g++ 2.95.

Quote:
The difference now is that
typically, if you expected to use the base class function, you
will get a compiler error in the template definition, rather
than in the instantiation. Unless, of course, you have a global
function with the same name -- in that case, your code will
silently behave differently, depending on the compiler you are
using.

Right, new errors and a higher chance of hijacking. My original
point again is that, had the new 2 phase rules been structured
differently, the inheritance rules would be consistent between
template and non-template classes.

Quote:
Once export becomes more widespread, of course, the problem will
disappear. Because you'll include the header with the template
as the first header in the implementation sources, and compile
it there, where you are sure that there are no extra, unwanted
global function declarations. If you want a base class member,
and forget the this->, you will get an error, independantly of
whatever other headers your client code may include before
yours.

If I have to type this->, the problem is still there.

Look, the standard is the way it is, and not likely to change.
You've more than answered my original question. Thanks for
the explanation.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.