Is it me or is it gcc?

B

Boltar

hi

I've come across a wierd template related error with gcc 3.4.6 on
linux. It doesn't occur with 3.3.3 or 4.2.1 so I'm wondering if its a
compiler bug or the compiler is just being extra pedantic (however
using -fpermissive makes no difference).

The error is:

$ c++ t.cc
t.cc: In member function `void n2<T>::test()':
t.cc:15: error: `wibble' was not declared in this scope
$

the code is:
template <typename T>
class n1
{
public:
int wibble;
};


template<typename T>
class n2: public n1<T>
{
public:
void test()
{
wibble = 1;
}
};


int main()
{
n2<int> n;
return 0;
}


It can be fixed by changing wibble=1 to this->wibble=1 but clearly
doing this in a large program for every single inherited base class
variable and function is not practical.

Anyone come across this before and know the solution or do we just
need to dump this version of gcc?

Thanks for any help

B2003
 
M

Michael DOUBEZ

Boltar a écrit :
hi

I've come across a wierd template related error with gcc 3.4.6 on
linux. It doesn't occur with 3.3.3 or 4.2.1 so I'm wondering if its a
compiler bug or the compiler is just being extra pedantic (however
using -fpermissive makes no difference).

The error is:

$ c++ t.cc
t.cc: In member function `void n2<T>::test()':
t.cc:15: error: `wibble' was not declared in this scope
$

the code is:
template <typename T>
class n1
{
public:
int wibble;
};


template<typename T>
class n2: public n1<T>
{
public:
void test()
{
wibble = 1;
}
};


int main()
{
n2<int> n;
return 0;
}


It can be fixed by changing wibble=1 to this->wibble=1 but clearly
doing this in a large program for every single inherited base class
variable and function is not practical.

Look up template-dependant name:
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19
Anyone come across this before and know the solution or do we just
need to dump this version of gcc?

I thought 4.2.1 would throw an error.
 
J

James Kanze

Thats just retarded. What idiot thought that up? Why would I
want "this->" in front of every inherited variable and class,
I might just as well code in C!

The problem is just the opposite. Suppose you have something
like:

extern int wibble ;
template< typename T >
class U : public T
{
public:
int f() { return wibble ; }
} ;

Now what happens if T contains a member wibble? (That's the
official reason---I'm not saying I agree with it.)

It has nothing to do with base classes or inheritance. It has
to do with whether the expression depends on the template
arguments or not. Without reason to do otherwise, "wibble",
used alone, doesn't depend on the template arguments, so is
looked up (and bound) immediately. Putting this-> in front of
it makes it depend on the template arguments (if there is a base
class which depends on the template arguments), so name lookup
and binding is deferred to instantiation time.
Perhaps the guys at GNU realise what a PITA this is and
removed the check.

I don't think so, but who knows.
 
B

Boltar

The problem is just the opposite. Suppose you have something
like:

extern int wibble ;
template< typename T >
class U : public T
{
public:
int f() { return wibble ; }
} ;

Now what happens if T contains a member wibble? (That's the
official reason---I'm not saying I agree with it.)

But in that example you're inheriting from a template type so yes, I
can see the problem there. In my example however I was inheriting from
one of my own classes that happened to take template definition
parameters. Its not the same thing.

If the template in my example had a member variable "wibble" it
wouldn't make any difference since its obvious from the code I'm
trying to access the member variable from my own class , not that of
any variables created with the template type because in that case I'd
have to do [template type var].wibble=1

B2003
 
B

Boltar

How so? In both cases below the compiler doesn't know anything about the
type derived from, since Foo could have specializations:

template<typename T> class U : public T;

template<typename T> class Foo { ... };
template<typename T> class U : public Foo<T>;

It doesn't in my example. For heavens sake , is it too much to ask a
compiler to know when specialisation is in use and when it isn't in
the same module for the same class?
I'd rather a compiler which followed well-defined rules rather than vague
things like "obvious", which differ from one person to the next. For one,
the compiler sees a lot more than the human does, in terms of all the
details.

Rubbish. These rules make it virtually impossible to use inheritence
with templates. Which rather defeats the point of using C++. As I said
earlier , I might as well use C. I'm pretty sure the compiler writers
have understood this which is why 4.2.1 doesn't error and just
compiles the code.

B2003
 
K

Kai-Uwe Bux

Boltar said:
It doesn't in my example. For heavens sake , is it too much to ask a
compiler to know when specialisation is in use and when it isn't in
the same module for the same class?


Rubbish. These rules make it virtually impossible to use inheritence
with templates.

I do that all the time. No problems here.

Which rather defeats the point of using C++. As I said
earlier , I might as well use C. I'm pretty sure the compiler writers
have understood this which is why 4.2.1 doesn't error and just
compiles the code.

I am pretty sure, compiler writers try to conform to the standard, which is
why I get an error on your test code

template <typename T>
class n1
{
public:
int wibble;
};


template<typename T>
class n2: public n1<T>
{
public:
void test()
{
wibble = 1;
}
};


int main()
{
n2<int> n;
return 0;
}


with gcc version

4.0.1
4.0.2
4.1.0
4.1.1
4.2.1
4.2.3
4.3.1


More specifically, I get:

xxx.cc: In member function 'void n2<T>::test()':
xxx.cc:15: error: 'wibble' was not declared in this scope

Could you check again whether the code passes 4.2.1?



Best

Kai-Uwe Bux
 
B

Bernd Strieder

Hello,
It doesn't in my example. For heavens sake , is it too much to ask a
compiler to know when specialisation is in use and when it isn't in
the same module for the same class?

A compiler cannot sensibly work in a way that it makes assumptions which
might be broken later on. If it took the wibble in your example as you
like it, somebody else could change your example by adding a
specialization for the base class and bring the compiler into trouble.

Older releases of gcc basically did some kind of textual insertion with
the macros at instantiation time, so all lookups happened at the point
that is now the second phase of lookup. The problem with that is, that
you basically could not have fixed meanings for names when the code is
parsed first time by the compiler, fixed in the sense that no later
specialization can change it. The first phase of name lookup for
templates ensures that this is possible.

Rubbish. These rules make it virtually impossible to use inheritence
with templates. Which rather defeats the point of using C++. As I said
earlier , I might as well use C. I'm pretty sure the compiler writers
have understood this which is why 4.2.1 doesn't error and just
compiles the code.

Then gcc 4.3 has reverted 4.2.1 again. 4.2.2 seems to have serious
problems with your example modified a little, it compiles the
following:

template <typename T>
class n1
{
public:
int wibble;
};


template<typename T>
class n2: public n1<T>
{
public:
void test()
{
this->wibble = 1;
//::wibble = 1; global variable
// wibble = 1; //this->wibble or ::wibble ?
// max(3,4)
/* this->max or std::max (with using namespace std) */
}
};

template<>
class n1<int>
{
public:
int wobble;
// int max(int,int);
};



int main()
{
n2<int> n;
n.test();
return 0;
}

Imagine you have something named wibble in the same namespace as n2. How
would you distinguish between that wibble and the wibble of class
template n1? Especially how would you do that at the point you are
parsing the body of your method test(), without making speculations? If
the compiler sees the wibble alone and took it as an argument-dependent
name, then suddenly all non-related names used within templates would
have to be fully qualified to distinguish them, think about the
max-example above. That would be quite a lot more work in non-trivial
templates than having to add this-> to make something
argument-dependent.

Bernd Strieder
 
A

Andrey Tarasevich

Boltar said:
It doesn't in my example. For heavens sake , is it too much to ask a
compiler to know when specialisation is in use and when it isn't in
the same module for the same class?

It is not a matter of whether it is "too much to ask " or not. It is a
matter of common sense. Having the semantics of _unqualified_ names to
be implicitly dependent on the template context would deal a huge amount
of damage to the readability of the code. It would be downright
dangerous. For these reasons C++ is pretty consistent in this regard:
the user has to explicitly acknowledge the "dependentness" of a name in
cases like that.
Rubbish. These rules make it virtually impossible to use inheritence
with templates. Which rather defeats the point of using C++.

No, quite the opposite. These rules are what keeps inheritance useful
with templates.
 
B

Boltar

A compiler cannot sensibly work in a way that it makes assumptions which
might be broken later on. If it took the wibble in your example as you
like it, somebody else could change your example by adding a
specialization for the base class and bring the compiler into trouble.

But the point is that there is no specialisation in that example. You
could use the same argument to say that ALL class member variables
must be qualified with their class name in case two or more classes
have variables with the same name. That clearly is crazy , just as
having to use "this->" in the above sort of template classes IMO.

B2003
 
B

Boltar

in the context of the 'main' above n2::test would refer to n1::wibble, while in
the context

template<> class n1<char> {};

struct MakeMyDay
{
void operator=( int ) { std::cout << "Dang!" << std::endl; }
} wibble;

void foo() { n2<char> n; n.test(); }

n2::test would refer to the global wibble, and cause an output operation.

But in that example just make the compiler give a duplicate
declaration or unknown scope error when it spots 2 objects/vars with
the same name. If there is only one variable in the whole program
called "wibble" why should it need to be qualified with "this->" ?

B2003
 
A

Andrey Tarasevich

Boltar said:
But the point is that there is no specialisation in that example. You
could use the same argument to say that ALL class member variables
must be qualified with their class name in case two or more classes
have variables with the same name. That clearly is crazy , just as
having to use "this->" in the above sort of template classes IMO.

How does two or more classes having variables with the same names could
lead to any ambiguity of the nature similar to the one in your original
example? Care to elaborate?
 
A

Andrey Tarasevich

Boltar said:
But in that example just make the compiler give a duplicate
declaration or unknown scope error when it spots 2 objects/vars with
the same name. If there is only one variable in the whole program
called "wibble" why should it need to be qualified with "this->" ?

Whole program? What "whole program"? C++ compiler doesn't see the "whole
program". Neither it is supposed to. The principle of independent
translation of translation units still remains one of the foundation
stones of C++ language.

In your previous posts you referred to a "module", instead of the "whole
program". That made more sense, assuming that by "module" you mean
"translation unit". It is indeed possible to analyze the entire
translation unit and come to the conclusion that your unqualified
'wibble' actually refers to the inherited 'wibble'. But that opens the
door to a rather hideous and unwelcome consequences, when the meaning if
the code at one point in the translation unit changes, depending on the
code located further down in the translation unit. While it is true,
that such change might occur in C++ in some other situations, the case
with an unqualified variable name is not one of them. And it shouldn't
be one of them, unless you want to turn the relevant C++ code into a
hopelessly obfuscated mess.
 
J

James Kanze

But in that example you're inheriting from a template type so
yes, I can see the problem there. In my example however I was
inheriting from one of my own classes that happened to take
template definition parameters. Its not the same thing.

Yes it is. The type of your base class depends on the argument
of the template.
If the template in my example had a member variable "wibble"
it wouldn't make any difference since its obvious from the
code I'm trying to access the member variable from my own
class, not that of any variables created with the template
type because in that case I'd have to do [template type
var].wibble=1

In your example, you inherited from a template, not a class.
The compiler cannot know the contents of this template until it
knows what the template argument will be, and it won't know that
until you instantiate the second template. (Think about
explicit specializations, for example.)
 
J

James Kanze

On 12 Sep, 18:09, Bernd Strieder <[email protected]>
wrote:
But the point is that there is no specialisation in that example.

But the point is that the compiler has no way of knowing that,
since the specialization is not required to be visible until the
template is actually instantiated.
You could use the same argument to say that ALL class member
variables must be qualified with their class name in case two
or more classes have variables with the same name.

No. A class is a class; it has only one definition. You
derived from template, which only becomes a class when
instantiated. And there are an infinite number of possible
instantiations.
That clearly is crazy , just as having to use "this->" in the
above sort of template classes IMO.

IMHO, it's not the ideal solution, but it certainly isn't crazy,
and it certainly doesn't make deriving from a dependent base
impossible.
 
J

James Kanze

It is not a matter of whether it is "too much to ask " or not.
It is a matter of common sense. Having the semantics of
_unqualified_ names to be implicitly dependent on the template
context would deal a huge amount of damage to the readability
of the code. It would be downright dangerous.

Don't exagerate. Template implementations existed for a long
time without dependent look-up, and there weren't any real
problems in practice. (Of course, existing "best practice" even
then said to always fully qualify such names anyway, using
::whatever or this->whatever to ensure that regardless of the
instantiation context, you got the symbol you wanted.)
For these reasons C++ is pretty consistent in this regard: the
user has to explicitly acknowledge the "dependentness" of a
name in cases like that.

IMHO, that's where there is a real problem. The user doesn't
explicitly state what is dependent or not; the compiler
"guesses" according to a fixed set of heuristics, and the user
has to then trick the compiler into guessing what he wants it to
guess. IMHO, 1) dependent names are a solution to something
that isn't a real problem in practice, and 2) if the distinction
is deemed desirable (because it does offer some protection),
then the user should state clearly which names are dependent,
and not have to second guess the heuristics the compiler uses
for guessing.
No, quite the opposite. These rules are what keeps inheritance
useful with templates.

Come now, inheritance was useful long before the rules were
adopted.
 
J

James Kanze

* Boltar:

[...]
Another and more practical solution is to add
using n1<T>::wibble;
in class n2.
Which isn't too bad.
But for a type you'd have to do something like
typedef typename n1<T>::SomeType SomeType;
which IMHO is bad.
It's really annoying, and verbose, and redundant, and silly.

Most of all, it's not orthogonal.

Have you thought of proposing to the committee that using work
also for types (in this context)? It's a bit late now, but I
suspect that it would have been viewed favorably earlier.
As others have remarked, it's a (language) feature, not a
bug... ;-)
As I understand it the rationale is that the definition of
class n2 should *mean the same* in every context it's used --
which might bring some conceptual clarity, might prevent bugs,
and might help with implementation of 'export' as well as a
compiler's use of some intermediate representation of the
template.

The rationale I heard was that it was to prevent name hijacking.
In his case, for example, if he'd wanted wibble to refer to a
global variable, a base class (or a specialization of the
template he used as a base class) which defined it would
"hijack" the name. By making it non-dependent, we ensure that
this cannot happen.
For example, if not for this rule, *or some other
disambiguation rule*, then in the context of the 'main' above
n2::test would refer to n1::wibble, while in the context
template<> class n1<char> {};
struct MakeMyDay
{
void operator=( int ) { std::cout << "Dang!" << std::endl; }
} wibble;
void foo() { n2<char> n; n.test(); }
n2::test would refer to the global wibble, and cause an output
operation.

Exactly. Except that the problem is more likely in the opposite
sense: he wanted some global, but picked up a name defined in
the base class.

And IMNO, you make a very good point with *or some other
disambiguation rule*. The actual rules for determining when a
symbol is dependent or not are fairly complex.
Thus, without this rule, *or some other disambiguation rule*,
the definition of class n2 would be very brittle, easily
"broken" simply by client code defining some global.

Earlier compilers didn't implement two phase look up, and we
didn't have problems with templates with them. And hey, this is
C++ anyway. Despite namespaces, dependent and non-dependent
names, and all the rest, the code is still "brittle", and will
be broken by the first unfortunate #define that comes along.
(That's why we have export.)
Personally I would rather have had the rule that in class
templates, use of global names would have to be qualified,
that all references were implicitly to class members unless
otherwise indicated.

That would certainly be simpler and easier to understand than
the current rules. But how is it to work with overloaded
operators and ADL?
I think that would have broken even more code than the
introduction of two-phase lookup did (history: template lookup
rules were changed at standardization). But I think, if code
was going to be broken anyway, it would have made sense to
care more about future than about past.

One could argue that such code was already broken, since it
allowed name hijacking. The best established practice in the
early days with templates was to fully qualify all names, to be
sure of getting the one you wanted (modulo macros, of course).
Disclaimer: I haven't really thought deep about the
qualify-globals-rule. Perhaps there's something that means it
wouldn't work.

Well, the way namespace works more or less makes ADL necessary,
and having to fully qualify a name turns that off.
 
J

Juha Nieminen

Boltar said:
Rubbish. These rules make it virtually impossible to use inheritence
with templates. Which rather defeats the point of using C++.

Wait a minute: You have to write "this->" in front of base class
member variable names in your derived class, and this makes it
IMPOSSIBLE to use inheritance with templates?

Are you nuts?

What next? If you want to access the member function of an object, you
have to write "objectName." or "objectName->" in front of that function
name, which makes it impossible to use objects in C++? If you want to
call a function, you have to write "(" before the function parameters
and ")" after them, and this makes it impossible to call functions in
C++? If you want to write a C++ program you have to write "int main("
somewhere, so this makes it impossible to write C++ programs.

Let me guess: You also always write a "using namespace" line in all
your source files to get rid of those pesky namespaces. After all, if
that was not possible, you would have to write "std::" in front of every
standard library name, which would make it IMPOSSIBLE to write any C++.
Lucky they added the "using namespace" trick, or else no programs could
be written.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top