Topic: Is this legal?
Author: barfurth@gmx.net (Joerg Barfurth)
Date: Mon, 14 Oct 2002 12:53:49 +0000 (UTC) Raw View
Hi,
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> I wonder if anyone can find the part of the Standard that allows
> defining a member function in a base class through a derived class
> specifier?=20
There is no such part. In fact I read 9.3/5 and 9.4.2/2 to disallow it.
But here we are looking at definitions of members of a nested class. For
this case 9.7/2 contains no similar wording. And I find nothing saying
that not both A::S and B::S would be valid class-names for class A::S.
In fact from 7.1.3/4 it looks as if any typedef name would do as well.
See also my reply o a mail by James Kanze later in this thread.
Regards, Joerg
--=20
J=F6rg Barfurth barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer http://util.openoffice.org
StarOffice Configuration # Deutsch:http://de.openoffice.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: barfurth@gmx.net (Joerg Barfurth)
Date: Mon, 14 Oct 2002 12:54:01 +0000 (UTC) Raw View
James Kanze <kanze@gabi-soft.de> wrote:
> > andys@evo6.com (Andy Sawyer) wrote
> > > Or how about:
>=20
> > > class A {
> > > public:
> > > static int s;
> > > };
>=20
> > > class B : public A { };
>=20
> > > int B::s =3D 0;
This luckily is illegal (see below).
> > > (Fortunatly - for my sanity at least - Comeau rejects this with the
> > > message "error: inherited member is not allowed")
=20
> > Is this a special-case for constructors?
>=20
> I don't think so.
Neither do I, but to me it seems restricted to the case of nested
classes.
> FWIW: I tried the following with all of the compilers I could get my
> hands on:
> // 1
> struct C // 2
> { // 3
> static int i ; // 4
> void f() ; // 5
> C() ; // 6
> ~C() ; // 7
> // 8
> struct S // 9
> { // 10
> static int i ; // 11
> void f() ; // 12
> S() ; // 13
> ~S() ; // 14
> } ; // 15
> } ; // 16
> // 17
> struct D : C // 18
> { // 19
> } ; // 20
> // 21
> int D::i =3D 0 ; // 22
My reading of 9.4.2/2 is that this is illegal. D certainly is not a
class-name of C. And i is a member of C, but not of D (cf. 9.2/1).
BTW: The wording 'its classname' is not really in sync with 7.1.3/4,
which award class-name status to typedef names, allowing an unbounded
number of classnames for a class.
> void D::f() {} // 24
Here the same argument applies: By 9.3/5 this is illegal.
> D::C() {} // 26
> D::~C() {} // 28
As pointed out earlier in this thread, the wording for Constructors and
Destructors is less clear. 12.1/1 and 12.4/1 seem to disallow defining
'structor functions out of class. For constructors this directly
contradicts the example in that paragraph. But I would assume that any
wording to fix this would at least inherit the restrictions of 9.3/5.
For constructors one might also find some argument against the above
being legal in the last sentence of 8/4.
> int D::S::i =3D 0 ; // 30
> void D::S::f() {} // 32
> D::S::S() {} // 34
> D::S::~S() {} // 36
Here I would assume that these definitions should be legal. D::S is a
classname of C::S. This would be just as legal as using a typedef
classname (7.1.3/4) in a member definition. An this seems to be
permitted from what I could find.
Interestingly 9.7/2 has no restriction like 9.3/5 or 9.4.2/2 have. Thus
for a nested class C::T, an out-of class definition as=20
class D::T { /*..*/ }
seems to be legal.
> I think, from my reading of the standard, that this program is fully
> legal. I don't want it to be, and I would very much appreciate it if
> someone could point out in the standard why it is illegal. =20
HTH.
Ciao, Joerg
Oh BTW: Except that it skips parsing line 28, being confused by line 26,
Comeau seems to agree with me:
> No compiler accepts it.
[...]
> Comeau on line 4.3.0.1:
> MODE:strict errors C++
>=20
> "ComeauTest.c", line 22: error: inherited member is not allowed
> int D::i =3D 0 ; // 22
> ^
>=20
> "ComeauTest.c", line 24: error: inherited member is not allowed
> void D::f() {} // 24
> ^
>=20
> "ComeauTest.c", line 26: error: expected an identifier
> D::C() {} // 26
> ^
>=20
> "ComeauTest.c", line 26: error: expected a ";" (perhaps on the
> previous statement)
> D::C() {} // 26
> ^
>=20
> "ComeauTest.c", line 30: warning: parsing restarts here after
> previous syntax error
> int D::S::i =3D 0 ; // 30
> ^
>=20
> 4 errors detected in the compilation of "ComeauTest.c".
--=20
J=F6rg Barfurth barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer http://util.openoffice.org
StarOffice Configuration # Deutsch:http://de.openoffice.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: a9804814@unet.univie.ac.at (Thomas Mang)
Date: Thu, 10 Oct 2002 21:24:46 +0000 (UTC) Raw View
>
>
> > Or how about:
>
> > class A {
> > public:
> > static int s;
> > };
>
> > class B : public A { };
>
> > int B::s = 0;
>
> > (Fortunatly - for my sanity at least - Comeau rejects this with the
> > message "error: inherited member is not allowed")
>
> I'd be interested in hearing the justification. By my reading of the
> standard, the code is perfectly legal, and the error is due to an error
> in the compiler.
>
> I hope you'll agree that the expression B::i is perfectly legal, and
> refers to the member variable i of B; member variable which is in B
> because B has inherited it from A.
As others, I have little idea about this being standard conforming or not,
however, I makes me worry if it would be (see below)
>
> I agree, but there is one argument for it: consistency. I can (and
> should be able to) refer to B::S in an expression, e.g.:
>
> B::S* ps = new B::S ;
>
> is definitely legal. And if it weren't, why the special treatment of
> constructors: B::f() can refer to a function in A, and B::i to a
> variable (static or otherwise) in A.
Here, your program uses B, and along with that it's definitions, including
the one it provides for members of A. So that doesn't cause a problem in THIS
code, as you use A and B together. What is not that obvious is that you HAVE
to use A and B together.
Expressed in another way, class A is fully link-time dependent on B.
Not on any other derived class(which, for example, overrides pure virtual
functions), but exactly on B.
I don't consider this to be really great neither for code reuse, nor for
maintainability.
But a nice method of forcing clients to use your whole class hierarchy......
You just place all the definitions for classes at the root of you hierarchy
into leaf classes, and have a good reason to sell the whole hierarchy
(including the never-get-used unimportant uninteresting odd useless buggy and
confusing classes) in a bundle.
best regards,
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Wed, 9 Oct 2002 17:52:47 +0000 (UTC) Raw View
> francis.glassborow@ntlworld.com (Francis Glassborow) writes:
> > How many people would be happy if this worked:
> >
> > class A {
> > public:
> > struct S { S(); };
> > };
> > class B : public A {
> > S::S(){}
> >
> > };
andys@evo6.com (Andy Sawyer) wrote
> Or how about:
>
> class A {
> public:
> static int s;
> };
>
> class B : public A { };
>
> int B::s = 0;
>
> (Fortunatly - for my sanity at least - Comeau rejects this with the
> message "error: inherited member is not allowed")
Is this a special-case for constructors?
I'd be just as unhappy if this worked:
class base {
private:
int b;
public:
base(int bb=0) : b(bb) {}
int foo(int);
int bar(int,int);
};
class der1 : public base {
int d1;
public:
der1(int dd1=0) : base(dd1+10), d1(dd1) {}
int baz() { return foo(d1); }
};
// base::foo defined here as der1::foo? (If this was legal)
int der1::foo(int i) {
// If this really is a member of base, then obviously it
// should not have access to d1, which may not exist.
// Also, base::foo should have access to base::x .
// But if it's defined as der1::foo, should it still have access?
return bar(i, x);
}
class der2 : public base {
int d2;
public:
der2(int dd2=0) : base(dd2+20), d2(dd2) {}
int baz() { return foo(d2); }
};
// base::bar defined here as der2::bar? (If this was legal)
int der2::bar(int j, int k) {
// Similar access questions
return bar(x+j*10+k*20);
}
int main() {
der1 d01(1);
der2 d02(2);
std::cout << d01.bar(100,200) << ' ' << d02.bar(300,400) << std::endl;
}
I can't easily quantify *why* I wouldn't want this to work --
as unlikely as this code is, if you told me it did work then I'd
have to say it has only one possible meaning. Nevertheless, it
shakes something up about the way I expect the language to work.
If foo() is declared in base, it should be defined there -- and
noplace else.
I notice that Todd Werme, the OP, hasn't said anything in this
thread since his initial post. Does anyone know if there is a
compiler that accepts some or all of the irregularities shown above?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Thu, 10 Oct 2002 17:36:35 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.0210090917.57fe52e2@posting.google.com>...
> > francis.glassborow@ntlworld.com (Francis Glassborow) writes:
> > > How many people would be happy if this worked:
> > > class A {
> > > public:
> > > struct S { S(); };
> > > };
> > > class B : public A {
> > > S::S(){}
> > > };
> andys@evo6.com (Andy Sawyer) wrote
> > Or how about:
> > class A {
> > public:
> > static int s;
> > };
> > class B : public A { };
> > int B::s = 0;
> > (Fortunatly - for my sanity at least - Comeau rejects this with the
> > message "error: inherited member is not allowed")
> Is this a special-case for constructors?
I don't think so.
FWIW: I tried the following with all of the compilers I could get my
hands on:
// 1
struct C // 2
{ // 3
static int i ; // 4
void f() ; // 5
C() ; // 6
~C() ; // 7
// 8
struct S // 9
{ // 10
static int i ; // 11
void f() ; // 12
S() ; // 13
~S() ; // 14
} ; // 15
} ; // 16
// 17
struct D : C // 18
{ // 19
} ; // 20
// 21
int D::i = 0 ; // 22
// 23
void D::f() {} // 24
// 25
D::C() {} // 26
// 27
D::~C() {} // 28
// 29
int D::S::i = 0 ; // 30
// 31
void D::S::f() {} // 32
// 33
D::S::S() {} // 34
// 35
D::S::~S() {} // 36
I think, from my reading of the standard, that this program is fully
legal. I don't want it to be, and I would very much appreciate it if
someone could point out in the standard why it is illegal. No
compiler
accepts it.
g++ 3.1:
derived.cc:22: ISO C++ does not permit `C::i' to be defined as
`D::i'
derived.cc:24: no `void D::f()' member function declared in class
`D'
derived.cc:26: parse error before `)' token
derived.cc:28: destructor `C' must match class name `D'
derived.cc:28: definition of implicitly-declared `D::~D()'
derived.cc:30: cannot declare member `C::S::i' within `D'
derived.cc:30: assignment (not initialization) in declaration
derived.cc:32: cannot declare member function `C::S::f' within `D'
derived.cc:32: syntax error before `{' token
derived.cc:34: cannot declare member function `C::S::S' within `D'
derived.cc:34: syntax error before `{' token
derived.cc:36: cannot declare member function `C::S::S' within `D'
derived.cc:36: syntax error before `{' token
Sun CC 5.1 (Sun Workshop 6):
"derived.cc", line 22: Error: i is not a member of D.
"derived.cc", line 24: Error: f() is not a member of D.
"derived.cc", line 26: Error: No direct declarator preceding "(".
3 Error(s) detected.
Comeau on line 4.3.0.1:
MODE:strict errors C++
"ComeauTest.c", line 22: error: inherited member is not allowed
int D::i = 0 ; // 22
^
"ComeauTest.c", line 24: error: inherited member is not allowed
void D::f() {} // 24
^
"ComeauTest.c", line 26: error: expected an identifier
D::C() {} // 26
^
"ComeauTest.c", line 26: error: expected a ";" (perhaps on the
previous statement)
D::C() {} // 26
^
"ComeauTest.c", line 30: warning: parsing restarts here after
previous syntax error
int D::S::i = 0 ; // 30
^
4 errors detected in the compilation of "ComeauTest.c".
So no compiler accepts it, but there doesn't seem to be much agreement
as to the number of errors either.
--
James Kanze mailto:jkanze@caicheuvreux.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Mon, 7 Oct 2002 15:45:50 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.0210021258.12698eb4@posting.google.com>...
> kanze@gabi-soft.de (James Kanze) wrote
> > Note that this is clarified by (or contradicted by) the last
> > sentence in 8: "A class-name has special meaning in a declartion of
> > the class of that name and when qualified by that name using the
> > scope resolution operator ::." Based on this sentence alone, it is
> > clear that both A::S::S and B::S::S are legal in the definition,
> > since both A::S and B::S are legal names for class S on the right
> > side of the scope resolution operator. So is C::S, if C is a
> > typedef for A::S (or B::S).
> > Anyhow, I'd like to see 12.1 cleaned up so that it agrees with 8,
> > but I think that given 8, the intent is clear.
> > The constructor has no name. According to the standard, a special
> > syntax is used to declare or define a constructor: within the class
> > itself, the class name (just C) is used; outside of the class, it is
> > necessary to use a scope operator in order to put oneself "into" the
> > class before using just the class name. The standard doesn't seem
> > to privilege any particular scope specification, however: derived
> > class names, typedef's, etc. all seem valid, as long as result
> > specifies the scope of the class whose destructor is being defined.
> > Note that the same thing is true for functions: a member function of
> > S could be defined as:
> > void A::S::f() {}
> > void B::S::f() {}
> > or void C::f() {}
> That helps a lot, James. Thank you. It's still confusing, but not
> nearly as bad as it used to be...
If it makes you feel better, I started my article by looking to quote
line and paragraph from the standard as to why this was illegal:-).
Live and learn -- after having studied the passages several times, I
went back and corrected the beginning of the article to reflect what I'd
learned.
> Perhaps a design goal for the next standard, would be to make the
> wording as clear as possible while still meeting the rigors of a
> standards document. Would it be possible to obtain the services of a
> technical writer? Perhaps as an incentive, this writer could be exempt
> from having to pay membership fees. -- Just a thought.
I don't think it's just that. Much of the standard was written by Andy
Koenig. A very gifted technical writer, to judge by everything else
he's written.
I too would like a solution, but I don't have one. (I am convinced that
writing a standard is several magnitudes more difficult than writing a
C++ program. Or even explaining a new C++ technique.)
--
James Kanze mailto:jkanze@caicheuvreux.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Mon, 7 Oct 2002 15:46:00 +0000 (UTC) Raw View
andys@evo6.com (Andy Sawyer) wrote in message
news:<smzo4p8q.fsf@ender.evo6.com>...
> francis.glassborow@ntlworld.com (Francis Glassborow) writes:
> > I wonder if anyone can find the part of the Standard that allows
> > defining a member function in a base class through a derived class
> > specifier? It seems to me that such code is particularly
> > ill-conceived
> Can we say "understatement"? I think we can :-)
I don't like it either, but the standard says...
> > and the example Andy gives highlights this. How many
> > people would be happy if this worked:
> > class A {
> > public:
> > struct S { S(); };
> > };
> > class B : public A {
> > S::S(){}
> > };
> Or how about:
> class A {
> public:
> static int s;
> };
> class B : public A { };
> int B::s = 0;
> (Fortunatly - for my sanity at least - Comeau rejects this with the
> message "error: inherited member is not allowed")
I'd be interested in hearing the justification. By my reading of the
standard, the code is perfectly legal, and the error is due to an error
in the compiler.
I hope you'll agree that the expression B::i is perfectly legal, and
refers to the member variable i of B; member variable which is in B
because B has inherited it from A.
> > We do not allow an alias name for a namespace to be used for adding
> > to a namespace (and that is a right pain) so how come that we allow
> > a far more dangerous define a base class member in the scope of a
> > derived class? If this really is allowed, we probably cannot fix it
> > because as sure as anything some legacy code uses it. But I think it
> > is a serious wart, not least because, IIUC, it allows silent change:
> > class A {
> > public:
> > struct S { S(); };
> > };
> > class B : public A { };
> > B::S::S(){}
> > defines A::S::S()
> > Now insert a struct S in B, hiding the version in the base class and
> > that definition magically now refers to B::S::S() and A::S::S()
> > becomes undefined.
> Or at lease ceases to be defined :-) (There's a reflex invoked here
> where the word "undefined" follows itself with
> "behaviour"). Fortunaty, this is unlikely to be a _silent_ change -
> there's a fair old chance that it will fail at link time.
> Regardless, I just thinks it's plain wrong that this works (or at
> least seems to).
I agree, but there is one argument for it: consistency. I can (and
should be able to) refer to B::S in an expression, e.g.:
B::S* ps = new B::S ;
is definitely legal. And if it weren't, why the special treatment of
constructors: B::f() can refer to a function in A, and B::i to a
variable (static or otherwise) in A.
--
James Kanze mailto:jkanze@caicheuvreux.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Wed, 2 Oct 2002 23:57:53 +0000 (UTC) Raw View
kanze@gabi-soft.de (James Kanze) wrote
> Note that this is clarified by (or contradicted by) the last sentence in
> 8: "A class-name has special meaning in a declartion of the class of
> that name and when qualified by that name using the scope resolution
> operator ::." Based on this sentence alone, it is clear that both
> A::S::S and B::S::S are legal in the definition, since both A::S and
> B::S are legal names for class S on the right side of the scope
> resolution operator. So is C::S, if C is a typedef for A::S (or B::S).
>
> Anyhow, I'd like to see 12.1 cleaned up so that it agrees with 8, but
> I think that given 8, the intent is clear.
> The constructor has no name. According to the standard, a special
> syntax is used to declare or define a constructor: within the
> class itself, the class name (just C) is used; outside of the class, it
> is necessary to use a scope operator in order to put oneself "into" the
> class before using just the class name. The standard doesn't seem to
> privilege any particular scope specification, however: derived class
> names, typedef's, etc. all seem valid, as long as result specifies the
> scope of the class whose destructor is being defined.
>
> Note that the same thing is true for functions: a member function of S
> could be defined as:
>
> void A::S::f() {}
> void B::S::f() {}
> or void C::f() {}
That helps a lot, James. Thank you. It's still confusing, but not
nearly as bad as it used to be...
Perhaps a design goal for the next standard, would be to make the
wording as clear as possible while still meeting the rigors of a
standards document. Would it be possible to obtain the services
of a technical writer? Perhaps as an incentive, this writer could
be exempt from having to pay membership fees. -- Just a thought.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Thu, 3 Oct 2002 01:55:20 +0000 (UTC) Raw View
andys@evo6.com (Andy Sawyer) wrote
> allan_w@my-dejanews.com (Allan W) writes:
>
> > > wilx@logout.sh.cvut.cz (VACLAV HAISMAN) wrote
> > > > Is this legal?
> > > >
> > > > class A {
> > > > public:
> > > > struct S { S(); };
> > > > };
> > > > class B : public A {};
> > > > B::S::S() {}
> >
> > allan_w@my-dejanews.com (Allan W) wrote
> > > ...if your question is about the syntax for defining the constructor
> > > of the embedded class, then yes I believe you have the correct syntax.
> >
> > But I didn't look closely enough.
> >
> > The full name of class S is A::S, not B::S. Therefore, the constructor
> > is declared A::S::S().
> >
> > The fact that B derives from A shouldn't matter at all, and I don't
> > understand why the Comeau compiler accepted the B::S::S() form.
For the record: I never meant to imply that "compiles without error
on some platform" equals "legal code."
> It gets wierder... I tried this (Comean 4.3.0.1, Win32):
>
> class A {
> public:
> struct S { S(); };
> };
> class B : public A {};
> class C : public A {};
>
> B::S::S() {}
> C::S::S() {}
>
> The given error was:
>
> function A::S::S() has already been defined.
>
> So clearly the compiler knows that both B::S::S() and C::S::S() are
> attempts to define the constructor in question (A::S::S()), just with
> "odd" names. I've filed a [possible] bug report with Comeau.
Consider that an attempt to use class S within either B or C, is
actually an attempt to use A::S. Without claiming a knowledge of
any compiler's internals, I'll speculate that there is some sort of
mapping going on, where B::S and C::S are simply redirected to the
implementation of A::S. This would also be important in the
definition of a template functions (and constructors).
The error, if there is one, is that the same indirection was applied
to non-template constructor (and probably function) definitions.
A useful exercise would be to compile this code and examine the error:
class A {
public:
struct S { S(); };
};
class B : public A {};
B::S::S() {
1=2; // Illegal assignment
}
When the compiler complains about the illegal assignment, what function
does it claim to have been compiling at the time? A::S::S or B::S::S?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andys@evo6.com (Andy Sawyer)
Date: Tue, 1 Oct 2002 23:34:40 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) writes:
> > wilx@logout.sh.cvut.cz (VACLAV HAISMAN) wrote
> > > Is this legal?
> > >
> > > class A {
> > > public:
> > > struct S { S(); };
> > > };
> > > class B : public A {};
> > > B::S::S() {}
>
> allan_w@my-dejanews.com (Allan W) wrote
> > ...if your question is about the syntax for defining the constructor
> > of the embedded class, then yes I believe you have the correct syntax.
>
> But I didn't look closely enough.
>
> The full name of class S is A::S, not B::S. Therefore, the constructor
> is declared A::S::S().
>
> The fact that B derives from A shouldn't matter at all, and I don't
> understand why the Comeau compiler accepted the B::S::S() form.
It gets wierder... I tried this (Comean 4.3.0.1, Win32):
class A {
public:
struct S { S(); };
};
class B : public A {};
class C : public A {};
B::S::S() {}
C::S::S() {}
The given error was:
function A::S::S() has already been defined.
So clearly the compiler knows that both B::S::S() and C::S::S() are
attempts to define the constructor in question (A::S::S()), just with
"odd" names. I've filed a [possible] bug report with Comeau.
Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Wed, 2 Oct 2002 01:41:50 +0000 (UTC) Raw View
On Tue, 1 Oct 2002 17:14:05 +0000 (UTC),
francis.glassborow@ntlworld.com (Francis Glassborow) wrote:
> class A {
> public:
> struct S { S();int i; };
A::S::S() is declared.
> };
> class B : public A {
> using A::S;
I think that brings S into B which makes the following invalid.
Comeau agrees. Moving the using after the struct makes the
using invalid since B already has an S.
> struct S { S();long i; };
> };
> B::S::S() {}
> //A::S::S(){}
> A::S s;
> IOWs declaring a new struct S in the derived class and defining it while
> not defining a ctor for A::S allowed the compiler (running in strict
> ANS/ISO mode) to claim that it had compiled my code without diagnostics.
Get rid of the using, and Comeau also accepts it. But Comeau online
does not link and I bet you didn't either. With or without the using,
g++ accepts the code and fails to link. Remove the S from B and the
B::S::S() does define the A::S::S() because it is another name for it.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andys@evo6.com (Andy Sawyer)
Date: Wed, 2 Oct 2002 02:47:23 +0000 (UTC) Raw View
jpotter@falcon.lhup.edu (John Potter) writes:
> On Tue, 1 Oct 2002 17:14:05 +0000 (UTC),
> francis.glassborow@ntlworld.com (Francis Glassborow) wrote:
>
> > class A {
> > public:
> > struct S { S();int i; };
>
> A::S::S() is declared.
>
> > };
> > class B : public A {
> > using A::S;
>
> I think that brings S into B which makes the following invalid.
> Comeau agrees. Moving the using after the struct makes the
> using invalid since B already has an S.
>
> > struct S { S();long i; };
> > };
> > B::S::S() {}
> > //A::S::S(){}
> > A::S s;
>
> > IOWs declaring a new struct S in the derived class and defining it while
> > not defining a ctor for A::S allowed the compiler (running in strict
> > ANS/ISO mode) to claim that it had compiled my code without diagnostics.
>
> Get rid of the using, and Comeau also accepts it. But Comeau online
> does not link and I bet you didn't either.
I can't speak for Francis, but as a data point I tried it with "Comeau
offline" :-). (Comeau 4.3.0.1 / Win 2000 / MSVC 6.0 backend)
With the using _before_ the struct declaration, compilation fails on
the struct declaration - "S has already been declared in the current
scope"
With the using _after_ the struct declaration, compilation fails on
the using delcaration - "S has already been declared in the current
scope"
Without the using, compilation succeeds but if fails to link -
"unresolved external symbol A::S::S()".
The original example (i.e. only one struct S, delcared in A, with the
ctor defined as B::S::S() ) compiles and links cleanly.
Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 2 Oct 2002 11:52:44 +0000 (UTC) Raw View
andys@evo6.com (Andy Sawyer) wrote in message
news:<adlxn3e6.fsf@ender.evo6.com>...
> allan_w@my-dejanews.com (Allan W) writes:
> > > wilx@logout.sh.cvut.cz (VACLAV HAISMAN) wrote
> > > > Is this legal?
> > > > class A {
> > > > public:
> > > > struct S { S(); };
> > > > };
> > > > class B : public A {};
> > > > B::S::S() {}
> > allan_w@my-dejanews.com (Allan W) wrote
> > > ...if your question is about the syntax for defining the constructor
> > > of the embedded class, then yes I believe you have the correct syntax.
> > But I didn't look closely enough.
> > The full name of class S is A::S, not B::S. Therefore, the
> > constructor is declared A::S::S().
Isn't B::S also a name for class S?
What if I add "typedef A::S C"? Isn't C a name for class S? Does the
compiler accept:
C::S() {}
? (Both g++ and Sun CC do.)
I'm not too sure what the standard tries to say. The exact text
( 12.1/1) is:
A special declarator syntax using an optional function-specifier
followed by the constructor's class name followed by a parameter
list is used to declare or define the constructor.
IMHO, this is simply wrong with regards to "define", as it would also
disallow A::S::S() {} (since A::S::S is NOT the constructor's class
name, A::S is). Given that the standard forbids the one way we know is
right, it is hard to say what it is trying to say.
Note that this is clarified by (or contradicted by) the last sentence in
8: "A class-name has special meaning in a declartion of the class of
that name and when qualified by that name using the scope resolution
operator ::." Based on this sentence alone, it is clear that both
A::S::S and B::S::S are legal in the definition, since both A::S and
B::S are legal names for class S on the right side of the scope
resolution operator. So is C::S, if C is a typedef for A::S (or B::S).
Anyhow, I'd like to see 12.1 cleaned up so that it agrees with 8, but
I think that given 8, the intent is clear.
> > The fact that B derives from A shouldn't matter at all, and I don't
> > understand why the Comeau compiler accepted the B::S::S() form.
> It gets wierder... I tried this (Comean 4.3.0.1, Win32):
> class A {
> public:
> struct S { S(); };
> };
> class B : public A {};
> class C : public A {};
> B::S::S() {}
> C::S::S() {}
> The given error was:
> function A::S::S() has already been defined.
> So clearly the compiler knows that both B::S::S() and C::S::S() are
> attempts to define the constructor in question (A::S::S()), just with
> "odd" names. I've filed a [possible] bug report with Comeau.
The constructor has no name. According to the standard, a special
syntax is used to declare or define a constructor: within the
class itself, the class name (just C) is used; outside of the class, it
is necessary to use a scope operator in order to put oneself "into" the
class before using just the class name. The standard doesn't seem to
privilege any particular scope specification, however: derived class
names, typedef's, etc. all seem valid, as long as result specifies the
scope of the class whose destructor is being defined.
Note that the same thing is true for functions: a member function of S
could be defined as:
void A::S::f() {}
void B::S::f() {}
or void C::f() {}
--
James Kanze mailto:jkanze@caicheuvreux.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andys@evo6.com (Andy Sawyer)
Date: Wed, 2 Oct 2002 17:12:46 +0000 (UTC) Raw View
kanze@gabi-soft.de (James Kanze) writes:
> andys@evo6.com (Andy Sawyer) wrote in message
> > So clearly the compiler knows that both B::S::S() and C::S::S() are
> > attempts to define the constructor in question (A::S::S()), just with
> > "odd" names. I've filed a [possible] bug report with Comeau.
>
> The constructor has no name.
I'm aware of that. I should have "quoted" names as well, and I
apologise for my sloppy terminology :-)
> Note that the same thing is true for functions: a member function of S
> could be defined as:
>
> void A::S::f() {}
> void B::S::f() {}
> or void C::f() {}
It would appear so - and I think it's unfortunate, but I can live with
it.
Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Wed, 2 Oct 2002 17:33:05 +0000 (UTC) Raw View
In article <adlxn3e6.fsf@ender.evo6.com>, Andy Sawyer <andys@evo6.com>
writes
>It gets wierder... I tried this (Comean 4.3.0.1, Win32):
>
> class A {
> public:
> struct S { S(); };
> };
> class B : public A {};
> class C : public A {};
>
> B::S::S() {}
> C::S::S() {}
>
>The given error was:
>
> function A::S::S() has already been defined.
>
>So clearly the compiler knows that both B::S::S() and C::S::S() are
>attempts to define the constructor in question (A::S::S()), just with
>"odd" names. I've filed a [possible] bug report with Comeau.
I wonder if anyone can find the part of the Standard that allows
defining a member function in a base class through a derived class
specifier? It seems to me that such code is particularly ill-conceived
and the example Andy gives highlights this. How many people would be
happy if this worked:
class A {
public:
struct S { S(); };
};
class B : public A {
S::S(){}
};
My compilers reject this, as I think they should, but how is that
actually different from the out of class definition? Well the reason for
regection is that I cannot _declare_ S::S() in B. But definitions are
always declarations are they not? Well perhaps out of class definitions
of members break this language 'invariant' and really are just
definitions.
We do not allow an alias name for a namespace to be used for adding to a
namespace (and that is a right pain) so how come that we allow a far
more dangerous define a base class member in the scope of a derived
class? If this really is allowed, we probably cannot fix it because as
sure as anything some legacy code uses it. But I think it is a serious
wart, not least because, IIUC, it allows silent change:
class A {
public:
struct S { S(); };
};
class B : public A { };
B::S::S(){}
defines A::S::S()
Now insert a struct S in B, hiding the version in the base class and
that definition magically now refers to B::S::S() and A::S::S() becomes
undefined.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andys@evo6.com (Andy Sawyer)
Date: Wed, 2 Oct 2002 21:01:06 +0000 (UTC) Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) writes:
> I wonder if anyone can find the part of the Standard that allows
> defining a member function in a base class through a derived class
> specifier? It seems to me that such code is particularly
> ill-conceived
Can we say "understatement"? I think we can :-)
> and the example Andy gives highlights this. How many
> people would be happy if this worked:
>
> class A {
> public:
> struct S { S(); };
> };
> class B : public A {
> S::S(){}
>
> };
Or how about:
class A {
public:
static int s;
};
class B : public A { };
int B::s = 0;
(Fortunatly - for my sanity at least - Comeau rejects this with the
message "error: inherited member is not allowed")
> We do not allow an alias name for a namespace to be used for adding to a
> namespace (and that is a right pain) so how come that we allow a far
> more dangerous define a base class member in the scope of a derived
> class? If this really is allowed, we probably cannot fix it because as
> sure as anything some legacy code uses it. But I think it is a serious
> wart, not least because, IIUC, it allows silent change:
>
> class A {
> public:
> struct S { S(); };
> };
> class B : public A { };
>
> B::S::S(){}
>
> defines A::S::S()
>
> Now insert a struct S in B, hiding the version in the base class and
> that definition magically now refers to B::S::S() and A::S::S() becomes
> undefined.
Or at lease ceases to be defined :-) (There's a reflex invoked here
where the word "undefined" follows itself with
"behaviour"). Fortunaty, this is unlikely to be a _silent_ change -
there's a fair old chance that it will fail at link time.
Regardless, I just thinks it's plain wrong that this works (or at
least seems to).
Regards,
Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: wilx@logout.sh.cvut.cz (=?iso-8859-1?Q?V=C1CLAV?= HAISMAN)
Date: Mon, 30 Sep 2002 17:07:29 +0000 (UTC) Raw View
Is this legal?
class A {
public:
struct S { S(); };
};
class B : public A {};
B::S::S() {}
Vaclav Haisman
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Tue, 1 Oct 2002 01:32:32 +0000 (UTC) Raw View
In article <slrnapc5sj.12f5.wilx@logout.sh.cvut.cz>, V=C1CLAV HAISMAN=20
<wilx@logout.sh.cvut.cz> writes
>Is this legal?
>
>class A {
>public:
> struct S { S(); };
>};
>class B : public A {};
>B::S::S() {}
class X{
void foo();
};
class Y : public X {};
do you expect:
void Y::foo(){};
to be legal? I hope not, because foo() is not declared in the scope of=20
Y, just inherited from X. The definition must be in the same scope as=20
the declaration. Now apply that to your question.
--=20
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Tue, 1 Oct 2002 08:42:00 +0000 (UTC) Raw View
wilx@logout.sh.cvut.cz (VACLAV HAISMAN) wrote
> Is this legal?
>
> class A {
> public:
> struct S { S(); };
> };
> class B : public A {};
> B::S::S() {}
I don't know about the laws in CZ (is that Czechoslovakia?).
Here in the United States, you've committed no crime by writing it.
...if your question is about the syntax for defining the constructor
of the embedded class, then yes I believe you have the correct syntax.
The Online Comeau compiler ( http://www.comeaucomputing.com/tryitout/ )
agrees with me.
Is there some compiler where this didn't work correctly?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "V clav Haisman" <V.Haisman@sh.cvut.cz>
Date: Tue, 1 Oct 2002 07:36:51 CST Raw View
It looks like there are two contradicting opinions about this.
I asked because GCC 3.2.x accepts it and I think it is at least strange and
I don't know the standard very well.
Could anybody with good knowledge of the standard make it clear if it is
wrong or right?
Vaclav Haisman
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Tue, 1 Oct 2002 17:14:05 +0000 (UTC) Raw View
In article <7f2735a5.0209301718.1823413f@posting.google.com>, Allan W
<allan_w@my-dejanews.com> writes
>> class A {
>> public:
>> struct S { S(); };
>> };
>> class B : public A {};
>> B::S::S() {}
>
>I don't know about the laws in CZ (is that Czechoslovakia?).
>Here in the United States, you've committed no crime by writing it.
>
>...if your question is about the syntax for defining the constructor
>of the embedded class, then yes I believe you have the correct syntax.
>The Online Comeau compiler ( http://www.comeaucomputing.com/tryitout/ )
>agrees with me.
Well it seems (despite my post late last night) that you are right.
Actually that makes me worried because the following also compiles when
I tested it quickly on MingW:
class A {
public:
struct S { S();int i; };
};
class B : public A {
using A::S;
struct S { S();long i; };
};
B::S::S() {}
//A::S::S(){}
A::S s;
IOWs declaring a new struct S in the derived class and defining it while
not defining a ctor for A::S allowed the compiler (running in strict
ANS/ISO mode) to claim that it had compiled my code without diagnostics.
Does anyone feel that this is wrong?
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Tue, 1 Oct 2002 19:56:28 +0000 (UTC) Raw View
> wilx@logout.sh.cvut.cz (VACLAV HAISMAN) wrote
> > Is this legal?
> >
> > class A {
> > public:
> > struct S { S(); };
> > };
> > class B : public A {};
> > B::S::S() {}
allan_w@my-dejanews.com (Allan W) wrote
> ...if your question is about the syntax for defining the constructor
> of the embedded class, then yes I believe you have the correct syntax.
But I didn't look closely enough.
The full name of class S is A::S, not B::S. Therefore, the constructor
is declared A::S::S().
The fact that B derives from A shouldn't matter at all, and I don't
understand why the Comeau compiler accepted the B::S::S() form.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: klaasjan elzinga <klaasjanelzingang@hotmail.com>
Date: Wed, 10 Apr 2002 16:23:05 GMT Raw View
ostringstream.operator<< returns ostringstream& and not const
ostringstream&.
The compiler was right. BTW dont overpost
KlaasJan Elzinga
Larry Brown wrote:
> Given the following:
>
> ////////////////////////////////////////////////////////////
> void SomeFunc(const ostringstream &Stream)
> {
> }
> SomeFunc(ostringstream() << 20);
> ////////////////////////////////////////////////////////////
>
> Is the above call legal? I believe it is but I get an error telling me the
> conversion can't be carried out because:
>
> "No constructor could take the source type, or constructor overload
> resolution was ambiguous"
>
> However, I can successfully call it like this:
>
> SomeFunc(static_cast<const ostringstream &>(ostringstream() << 20));
>
> Is my standard library (or compiler) simply not with the times?
>
>
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Mike Wahler" <mkwahler@ix.netcom.com>
Date: Wed, 10 Apr 2002 20:28:19 GMT Raw View
klaasjan elzinga <klaasjanelzingang@hotmail.com> wrote in message
news:3CB42032.30105@hotmail.com...
> ostringstream.operator<< returns ostringstream& and not const
> ostringstream&.
No, it returns type 'std::ostream&'
OP's function should be:
void SomeFunc(const std::ostream& Stream)
{
}
-Mike
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: Mon, 28 Jan 2002 18:40:17 GMT Raw View
> >
> > template <bool> struct X {};
> >
> > template <class T, T* p> struct Y
> > {
> > void f()
> > {
> > X<p & 1> x; // legal? possible?
> > }
> > };
>
> This isn't legal.
>
> 14.3.2/1 states that a non-type template parameter must be an integral
> constant-expression, ...
Not to mention the fact that you can't apply the & operation to a pointer.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Mon, 28 Jan 2002 19:32:21 GMT Raw View
Richard Smith <richard@ex-parrot.com> escribi=F3 en el mensaje de noticia=
s
1012239829.24395.0.nnrp-02.3e31d362@news.demon.co.uk...
>
> "Carl Daniel" <cpdaniel@pacbell.net> wrote in message
> news:zFs48.36901$n66.2595776626@newssvr21.news.prodigy.com...
> > One thing the compiler couldn't do is make any assumptions at compile
> time.
> > Even though the pointer value is a constant, it's a constant unknown =
to
> the
> > compiler, so it'd have to generate code to evaluate expressions which
> would
> > otherwise be compile-time evaluated.
> >
> > I suppose that could lead to some interesting impossibilities (or may=
be
> > they're possible - it might be worth trying to find out what various
> > compilers do! and/or digging into the Standard to see what it says -
> maybe
> > tomorrow :-)
> >
> > Consider:
> >
> > template <bool> struct X {};
> >
> > template <class T, T* p> struct Y
> > {
> > void f()
> > {
> > X<p & 1> x; // legal? possible?
> > }
> > };
>
> This isn't legal.
>
> 14.3.2/1 states that a non-type template parameter must be an integral
> constant-expression, a non-type template parameter, an object or functi=
on
> with external linkage or a member-pointer. Clearly, if it is any of th=
ese
> it is the first. Constant-expressions are defined in 5.19, and integra=
l
> constant-expressions are defined in 5.19/1, and are only allowed to
"involve
> literals, enumerators, const variables or static data members of integr=
al
or
> enumeration types, and sizeof expressions." (And, in certain cases,
floating
> literals.) The variable p is none of these, and so is not allowed in a
> integral constant-expression.
>
> --
> Richard Smith
>
>
I take that you are referring to the expression: (p & 1).
In that case, you're right, but it is irrelevant to the point being made =
by
Carl.
He's showing that the only problems can come from metaprogramming, were t=
he
compile-time value of 'p' is being used somehow.
He also shows that any "runtime" usage of 'p' should be safe in that by t=
he
time it executes, 'p' will have the correct value.
Anyway, I must insist on the point shown by Eduardo: He was referring to
problems that could come from specialization, which is compile time
matching; not to runtime problems.
In those cases, someone writing the specialization, that is, instructing =
the
compiler to match the external address value with something, might encoun=
ter
an unexpected result.
Consider this:
template <class T, T* p> struct Y ;
template <class T, 0x1234> struct Y {} ;
I might know that 0x1234 belongs to a specific memory region and I might
want 'Y' to behave in some special way if 'p' is inside that area. But th=
is
won't work since 'p' won't have a real memory address so the matching won=
't
find the specialization.
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Mon, 28 Jan 2002 19:49:58 GMT Raw View
Sorry, too quick typing... the example should be:
template <class T, T* p> struct Y ;
template<> struct Y<MyClass,(MyClass*)(0x1234)> {} ;
I might know that 0x1234 belongs to a specific memory region and I might
want 'Y<MyClass>' to behave in some special way if 'p' is inside that area.
But this
won't work since 'p' won't have a real memory address so the matching won't
find the specialization.
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Mon, 28 Jan 2002 20:53:05 GMT Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a349tf$14s72h$1@ID-44132.news.dfncis.de...
> Sorry, too quick typing... the example should be:
>
> template <class T, T* p> struct Y ;
>
> template<> struct Y<MyClass,(MyClass*)(0x1234)> {} ;
>
> I might know that 0x1234 belongs to a specific memory region and I might
> want 'Y<MyClass>' to behave in some special way if 'p' is inside that
area.
> But this
> won't work since 'p' won't have a real memory address so the matching
won't
> find the specialization.
>
I believe that construct to be illegal. 14.3.2/1 says:
14.3.2 Template non-type arguments
A template-argument for anon-type, non-template template parameter shall be
one of:
- an integral constant-expression of integral or enumeration type; or
- the name of a non-type template parameter; or
- the name of an object or function with external linkage, including
function templates and function template-ids but excluding non-static class
members, expressed as id-expression; or
- the address of an object or function with external linkage, including
function template and function template-ids, but excluding non-static class
members, expressed as & id-expression where the & is optional if the name
refers to a function or array; or
- a pointer to member expressed as described in 5.3.1.
The expression (MyClass*)0x1234 does not fit any of these cases.
The example I proposed earlier (p & 1) is illegal for the same reason.
Attempting to cast p to int does not help - the result is an integral
expression, but not a constant-expression (according to 5.19), therefore
it's not a valid template non-type argument.
-cd
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Mon, 28 Jan 2002 22:20:53 GMT Raw View
Carl Daniel <cpdaniel@pacbell.net> escribi=F3 en el mensaje de noticias
yCi58.38263$tn4.3337027762@newssvr21.news.prodigy.com...
>
> "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> news:a349tf$14s72h$1@ID-44132.news.dfncis.de...
> > Sorry, too quick typing... the example should be:
> >
> > template <class T, T* p> struct Y ;
> >
> > template<> struct Y<MyClass,(MyClass*)(0x1234)> {} ;
> >
> > I might know that 0x1234 belongs to a specific memory region and I mi=
ght
> > want 'Y<MyClass>' to behave in some special way if 'p' is inside that
> area.
> > But this
> > won't work since 'p' won't have a real memory address so the matching
> won't
> > find the specialization.
> >
>
> I believe that construct to be illegal. 14.3.2/1 says:
>
> 14.3.2 Template non-type arguments
>
> A template-argument for anon-type, non-template template parameter shal=
l
be
> one of:
> - an integral constant-expression of integral or enumeration type; or
> - the name of a non-type template parameter; or
> - the name of an object or function with external linkage, including
> function templates and function template-ids but excluding non-static
class
> members, expressed as id-expression; or
> - the address of an object or function with external linkage, including
> function template and function template-ids, but excluding non-static
class
> members, expressed as & id-expression where the & is optional if the na=
me
> refers to a function or array; or
> - a pointer to member expressed as described in 5.3.1.
>
> The expression (MyClass*)0x1234 does not fit any of these cases.
>
> The example I proposed earlier (p & 1) is illegal for the same reason.
> Attempting to cast p to int does not help - the result is an integral
> expression, but not a constant-expression (according to 5.19), therefor=
e
> it's not a valid template non-type argument.
>
> -cd
>
According to Comeau C/C++ 4.2.45.2 online you're right.
It appears that there are very small chances that someone would use this
kind of template arguments in metaprogramming, so I think that it is pret=
ty
safe.
Anyway, I've notice that according to Comeau online you can do
template<> struct Y<MyClass,(MyClass*)(0)> {} ;
which makes sense, since ((MyClass*)(0)) qualifies since its a null point=
er
value.
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: eduardomadrid@hotmail.com (Eduardo Alberto Madrid Colmenares)
Date: Tue, 29 Jan 2002 03:39:06 GMT Raw View
I'm Impressed by your knowledge of the Standard!, nevertheless I still
believe that some people are missing something important if they think
that using external linkage addresses as template parameters is safe.
It is true that if the compiler just delegates on the linker, things
will be just fine, but inadvertedly you can fool the compiler. Here
is a concrete example that illustrates the problem:
extern int OperatingSystemResource;
/* The linker knows the address of this variable, architecture
dependent */
template <int *arena> struct AHA {
int *resource_at;
AHA(): resource_at(arena) {}
virtual ~AHA() { /* memory arena management here */ }
};
// It is nice to let the OS do some management. So, we provide an
// Specialization for the previous template, in the case the arena
address
// is handled by the OS. Nothing rare until now
template<> struct AHA<&OperatingSystemResource> {
AHA() {} // nothing to be done
virtual ~AHA() {} // the OS will take care in this arena
};
extern int AGlobalVariable;
AHA<&AGlobalVariable> TheObject; // Here the problem manifests. The
// compiler knows neither &OperatingSystemResource, nor
&AGlobalVariable
// but we are forcing it to know.
You can check if this code is adherent to the standard, I humbly
believe it is. You can see that when it tries to construct the type
AHA<&AGlobalVariable>, the compiler does NOT know the value of
&AGlobalVariable, so, it can not test it against the value in the
specialization; nevertheless it does, and without complaints!!! (At
least g++ 2.95 compiles this very silently)
This shows my point, which is: "it is NOT safe". Not having as deep
knowledge of the standard as I've seen you do, I started to believe
that I was wrong, but, no, common sense convinced me.
When I first heard about F. Cacciola's question, I immediately
realized that something was wrong, because you can not make the
compiler use a value that it doesn't know to construct a type. And it
took me a while to conceive the counter example. Then, I read a very
interesting discussion about the rules for template parameters, that
seemed to cancel a possibility in which the compiler had to really
consider the value instead of delegating it to the linker, but I think
that here it is that counter example.
Even, in different translation units, the results can vary, beacause
most likely, the actual value that the compiler might be using is the
symbols' table entry of the variables, and you can not expect them to
be exactly the same in different translation units.
Please, keep on discussing this issue!, I really wanna know if I'm
right!
-= Ed =-
> > "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> > news:a349tf$14s72h$1@ID-44132.news.dfncis.de...
> > > Sorry, too quick typing... the example should be:
> > >
> > > template <class T, T* p> struct Y ;
> > >
> > > template<> struct Y<MyClass,(MyClass*)(0x1234)> {} ;
> > >
> > > I might know that 0x1234 belongs to a specific memory region and I mi
> ght
> > > want 'Y<MyClass>' to behave in some special way if 'p' is inside that
> area.
> > > But this
> > > won't work since 'p' won't have a real memory address so the matching
> won't
> > > find the specialization.
> > >
> >
> > I believe that construct to be illegal. 14.3.2/1 says:
> >
> > 14.3.2 Template non-type arguments
> >
> > A template-argument for anon-type, non-template template parameter shal
> l
> be
> > one of:
> > - an integral constant-expression of integral or enumeration type; or
> > - the name of a non-type template parameter; or
> > - the name of an object or function with external linkage, including
> > function templates and function template-ids but excluding non-static
> class
> > members, expressed as id-expression; or
> > - the address of an object or function with external linkage, including
> > function template and function template-ids, but excluding non-static
> class
> > members, expressed as & id-expression where the & is optional if the na
> me
> > refers to a function or array; or
> > - a pointer to member expressed as described in 5.3.1.
> >
> > The expression (MyClass*)0x1234 does not fit any of these cases.
> >
> > The example I proposed earlier (p & 1) is illegal for the same reason.
> > Attempting to cast p to int does not help - the result is an integral
> > expression, but not a constant-expression (according to 5.19), therefor
> e
> > it's not a valid template non-type argument.
> >
> > -cd
> >
> According to Comeau C/C++ 4.2.45.2 online you're right.
> It appears that there are very small chances that someone would use this
> kind of template arguments in metaprogramming, so I think that it is pret
> ty
> safe.
>
> Anyway, I've notice that according to Comeau online you can do
>
> template<> struct Y<MyClass,(MyClass*)(0)> {} ;
>
> which makes sense, since ((MyClass*)(0)) qualifies since its a null point
> er
> value.
>
>
> --
> Fernando Cacciola
> Sierra s.r.l.
> fcacciola@gosierra.com
> www.gosierra.com
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Tue, 29 Jan 2002 10:05:04 CST Raw View
"Eduardo Alberto Madrid Colmenares" <eduardomadrid@hotmail.com> wrote in
message news:73050ec6.0201281928.966e881@posting.google.com...
> I'm Impressed by your knowledge of the Standard!, nevertheless I still
> believe that some people are missing something important if they think
> that using external linkage addresses as template parameters is safe.
> It is true that if the compiler just delegates on the linker, things
> will be just fine, but inadvertedly you can fool the compiler. Here
> is a concrete example that illustrates the problem:
[example snipped]
> You can check if this code is adherent to the standard, I humbly
> believe it is. You can see that when it tries to construct the type
> AHA<&AGlobalVariable>, the compiler does NOT know the value of
> &AGlobalVariable, so, it can not test it against the value in the
> specialization; nevertheless it does, and without complaints!!! (At
> least g++ 2.95 compiles this very silently)
Actually, it CAN and does test it against the value
&OperatingSystemResource, and correctly instantiates the un-specialized
version of the template. It tests it simply by seeing that it has a
different name. Since objects with external linkage have names, and must
have the same name in all translation units (otherwise they're not the same
object), the compiler need not know the value of the address in order to
make the comparison. Different name, different object. Period. Rember
that to be a valid non-type template argument, it must appear in the form &
id-expression (in other words, the address-of operator, followed by a name,
qualified or otherwise). You cannot fool the compiler by constructing an
address expression which happens to yield a value corresponding to a
specialization - these are not legal non-type template parameters.
Try this simple demonstration program with your compiler of choice:
---------------Begin Example---------------------
#include <iostream>
using namespace std;
template <int* p>
struct X
{
X(const char* sz)
{
cout << "X<int*>::X('" << sz << "') = " << *p << "\n";
}
};
extern int a = 5;
extern int b = 10;
template <>
struct X<&a>
{
X(const char* sz)
{
cout << "X<&a>::X('" << sz << "') = " << *p << "\n";
}
};
template <>
struct X<&b>
{
X(const char* sz)
{
cout << "X<&b>::X('" << sz << "') = " << *p << "\n";
}
};
extern int c=15;
int main()
{
X<&a> x1("x1");
X<&b> x2("x2");
X<&c> x3("x3");
return 0;
}
---------------End Example---------------------
You can split this up into as many translation units as you please and
you'll still get the same result (or if you don't your compiler is broken):
X<&a>::X('x1') = 5
X<&b>::X('x2') = 10
X<int*>::X('x3') = 15
Clearly the compiler CAN compare the addresses of variable which it doesn't
know at compile time, and instantiate the correct specialization for
whichever object you use.
-cd
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Tue, 29 Jan 2002 10:22:58 CST Raw View
Eduardo Alberto Madrid Colmenares wrote:
>
> I'm Impressed by your knowledge of the Standard!, nevertheless I still
> believe that some people are missing something important if they think
> that using external linkage addresses as template parameters is safe.
> It is true that if the compiler just delegates on the linker, things
> will be just fine, but inadvertedly you can fool the compiler. Here
> is a concrete example that illustrates the problem:
>
> extern int OperatingSystemResource;
> /* The linker knows the address of this variable, architecture
> dependent */
>
> template <int *arena> struct AHA {
> int *resource_at;
> AHA(): resource_at(arena) {}
> virtual ~AHA() { /* memory arena management here */ }
> };
>
> // It is nice to let the OS do some management. So, we provide an
> // Specialization for the previous template, in the case the arena
> address
> // is handled by the OS. Nothing rare until now
> template<> struct AHA<&OperatingSystemResource> {
> AHA() {} // nothing to be done
> virtual ~AHA() {} // the OS will take care in this arena
> };
>
> extern int AGlobalVariable;
>
> AHA<&AGlobalVariable> TheObject; // Here the problem manifests. The
> // compiler knows neither &OperatingSystemResource, nor
> &AGlobalVariable
> // but we are forcing it to know.
>
> You can check if this code is adherent to the standard, I humbly
> believe it is. You can see that when it tries to construct the type
> AHA<&AGlobalVariable>, the compiler does NOT know the value of
> &AGlobalVariable, so, it can not test it against the value in the
> specialization; nevertheless it does, and without complaints!!! (At
> least g++ 2.95 compiles this very silently)
Just because the compiler doesn't know what the value of those addresses
are, that doesn't mean it doesn't know enough to determine whether the
specialization applies. Since they're both defined with extern, they
can't be the same object, and therefore can't have the same address, and
that's enough for the compiler to know that the specialization is not
applicable.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Tue, 29 Jan 2002 10:23:16 CST Raw View
"Ron Natalie" <ron@sensor.com> wrote in message
news:3C559B49.FD1DF7B6@sensor.com...
>
> > >
> > > template <bool> struct X {};
> > >
> > > template <class T, T* p> struct Y
> > > {
> > > void f()
> > > {
> > > X<p & 1> x; // legal? possible?
> > > }
> > > };
> >
> > This isn't legal.
> >
> > 14.3.2/1 states that a non-type template parameter must be an integral
> > constant-expression, ...
>
> Not to mention the fact that you can't apply the & operation to a pointer.
True. When I actually tried the code in Comeau, I had a
reinterpret_cast<int> in there too.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Tue, 29 Jan 2002 10:28:22 CST Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a348m6$15bpl6$1@ID-44132.news.dfncis.de...
Richard Smith <richard@ex-parrot.com> escribi en el mensaje de noticias
1012239829.24395.0.nnrp-02.3e31d362@news.demon.co.uk...
[ ... ]
> > > Consider:
> > >
> > > template <bool> struct X {};
> > >
> > > template <class T, T* p> struct Y
> > > {
> > > void f()
> > > {
> > > X<p & 1> x; // legal? possible?
> > > }
> > > };
> >
> > This isn't legal.
> >
> > 14.3.2/1 states that a non-type template parameter must be an integral
> > constant-expression, a non-type template parameter, an object or
function
> > with external linkage or a member-pointer. Clearly, if it is any of
these
> > it is the first. Constant-expressions are defined in 5.19, and integral
> > constant-expressions are defined in 5.19/1, and are only allowed to
> "involve
> > literals, enumerators, const variables or static data members of
integral
> or
> > enumeration types, and sizeof expressions." (And, in certain cases,
> floating
> > literals.) The variable p is none of these, and so is not allowed in a
> > integral constant-expression.
> >
> > --
> > Richard Smith
> >
> >
> I take that you are referring to the expression: (p & 1).
Yes. Or more specifically, the 'p' bit on it's own.
> In that case, you're right, but it is irrelevant to the point being made
by
> Carl.
> He's showing that the only problems can come from metaprogramming, were
the
> compile-time value of 'p' is being used somehow.
The only way that I can think of to use the value of 'p' explicitly at
compile time, is by using it to instantiate a template, specifically by
using it as a non-type template parameter. Non-type template parameters can
be of the following forms:
- an integral constant-expression of integral or enumeration type; or
- the name of a non-type template parameter; or
- the name of an object or function with external linkage, including
function templates and function template-ids but excluding non-static
class
members, expressed as id-expression; or
- the address of an object or function with external linkage, including
function template and function template-ids, but excluding non-static
class
members, expressed as & id-expression where the & is optional if the
name
refers to a function or array; or
- a pointer to member expressed as described in 5.3.1.
Clearly 'p' cannot be used to form a pointer-to-member, and it is not
(directly) the name or address of an external object or functionin the form
id-expression or & id-expression. (Yes, it is indirectly, but it is
actually a non-type template parameter and so isn't in the required forms.)
Thus 'p' can only be used in a non-type template parameter in the first two
cases. The second case, just passes 'p' without modification to another
template parameter and so doesn't allow us use any properties of 'p', this
just leaves the first case -- integral constant-expressions -- which, as I
said in my previous post, cannot involve pointer types such as 'p' other
than in sizeof() expressions.
This seems to have ruled out all the ways of using any runtime information
about the pointer at compile time that I can think of. If you can see any
other way of using that information, I'd be interested to see them.
> He also shows that any "runtime" usage of 'p' should be safe in that by
the
> time it executes, 'p' will have the correct value.
>
> Anyway, I must insist on the point shown by Eduardo: He was referring to
> problems that could come from specialization, which is compile time
> matching; not to runtime problems.
[ I've dealt with that specific case in another post in this thread. ]
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Tue, 29 Jan 2002 14:32:43 CST Raw View
"Eduardo Alberto Madrid Colmenares" <eduardomadrid@hotmail.com> wrote in
message news:73050ec6.0201281928.966e881@posting.google.com...
> I'm Impressed by your knowledge of the Standard!, nevertheless I still
> believe that some people are missing something important if they think
> that using external linkage addresses as template parameters is safe.
> It is true that if the compiler just delegates on the linker, things
> will be just fine, but inadvertedly you can fool the compiler. Here
> is a concrete example that illustrates the problem:
>
> extern int OperatingSystemResource;
> /* The linker knows the address of this variable, architecture
> dependent */
>
> template <int *arena> struct AHA {
> int *resource_at;
> AHA(): resource_at(arena) {}
> virtual ~AHA() { /* memory arena management here */ }
> };
>
> // It is nice to let the OS do some management. So, we provide an
> // Specialization for the previous template, in the case the arena
> address
> // is handled by the OS. Nothing rare until now
> template<> struct AHA<&OperatingSystemResource> {
> AHA() {} // nothing to be done
> virtual ~AHA() {} // the OS will take care in this arena
> };
>
> extern int AGlobalVariable;
>
> AHA<&AGlobalVariable> TheObject; // Here the problem manifests. The
> // compiler knows neither &OperatingSystemResource, nor
> &AGlobalVariable
> // but we are forcing it to know.
As far as the Standard is concerned, &AGlobalVariable must be different from
&AGlobalVariable because the objects have different names. C++ has no
mechanism (other than references) to assign multiple names to the same
object, and so it is not possible to write Standard-compliant C++ code that
assigns the names OperatingSystemResource and AGlobalVariable. (In many
environments it is actually possible, either with some non-standard
extension or with some other tool, but these are beyond the remit of the
Standard.) The compiler can therefore assume that AGlobalVariable and
OperatingSystemResource are different objects, and thus assume that they
have different addresses.
In C++, the only object aliasing mechanism is references, and 14.3.2
prohibits the use of addresses of references as template parameters (they
are neither objects nor functions). So, for example,
extern int &AGlobalVariable;
AHA<&AGlobalVariable> TheObject;
is not legal.
> You can check if this code is adherent to the standard, I humbly
> believe it is. You can see that when it tries to construct the type
> AHA<&AGlobalVariable>, the compiler does NOT know the value of
> &AGlobalVariable, so, it can not test it against the value in the
> specialization; nevertheless it does, and without complaints!!! (At
> least g++ 2.95 compiles this very silently)
As indeed it should: the code is perfectly valid.
> This shows my point, which is: "it is NOT safe".
It's not the use of non-type pointer template parameters that I is unsafe;
it's the use of a external object that are pretending to be C++ objects, but
that might have semantics that C++ does not allow (e.g. multiple names) that
is unsafe
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: eduardomadrid@hotmail.com (Eduardo Alberto M C)
Date: Thu, 24 Jan 2002 22:33:25 CST Raw View
If you wanna know, I was initially surprised too, and checked its
behaviour in g++ 2.95.3, and it also worked.
I think that your construct is "legal", but unsafe:
The compiler, instantiating A with int and &global uses the "will be
known" address for "global", and puts it in the static method. After,
the linker resolves that reference and puts there the right address.
So, it compiles without complaint, and even works in this case.
But (Haven't tested it yet) I'd bet that if you'd created an
specialization of that template based, let's say for example, in
whether bit 4 of &global is true or not, it will fail miserably;
because what I call "the will be known address" is garbage (probably
an index into the compiler symbol table). The difference here lies in
the fact that the compiler doesn't care about the value of the
template parameter in your example, but to specialize the template, it
would have to.
Finally, the short answer to your question "How can I use extern
addresses..." can be: there is no safe way. Even in this case, if
your compiler used external template instantiation, (which is not the
case neither in g++ not in BCPP) it would not have worked as expected.
-= Ed =-
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams"<anthwil@nortelnetworks.com>
Date: Fri, 25 Jan 2002 15:18:36 GMT Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
> Consider the following:
> template<class T, T* val>
> struct A
> {
> static T val() { return *val ; }
> } ;
>
> extern int global ;
> typedef A<int,&global> Int_A ;
> int main()
> {
> int v = Int_A::val();
> }
> source_B.cpp
> ~~~~~~~~~~
> int global = 3 ;
>
>
> Is it legal?
> How can I use the address of a external variable as a template parameter.
> I mean, it is unknown at compile time, isn't it?
> The trick I've used seems to work as far as Borland is concerned, but it
is
> portable?
Yes.
Global variables are required to have the same address when accessed from
all translation units (otherwise they're not global). Also, two unrelated
objects may not have the same address. Therefore the compiler knows that
&global must be a single address across all translation units, and can emit
code that assumes this, and makes the linker determine the precise value
where needed.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: eduardomadrid@hotmail.com (Eduardo Alberto M C)
Date: Fri, 25 Jan 2002 17:56:04 GMT Raw View
"Anthony Williams"<anthwil@nortelnetworks.com> wrote in message news:<a2rahd$cqs$1@bcarh8ab.ca.nortel.com>...
> "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
> > Consider the following:
>
> > template<class T, T* val>
> > struct A
> > {
> > static T val() { return *val ; }
> > } ;
> >
> > extern int global ;
> > typedef A<int,&global> Int_A ;
>
> > int main()
> > {
> > int v = Int_A::val();
> > }
>
> > source_B.cpp
> > ~~~~~~~~~~
> > int global = 3 ;
> >
> >
> > Is it legal?
> > How can I use the address of a external variable as a template parameter.
> > I mean, it is unknown at compile time, isn't it?
>
> > The trick I've used seems to work as far as Borland is concerned, but it
> is
> > portable?
>
> Yes.
>
> Global variables are required to have the same address when accessed from
> all translation units (otherwise they're not global). Also, two unrelated
> objects may not have the same address. Therefore the compiler knows that
> &global must be a single address across all translation units, and can emit
> code that assumes this, and makes the linker determine the precise value
> where needed.
>
That's true, however, better be careful. It is the *LINKER* who
puts the right value _inside_ the templates, therefore, the value of
&global _can_ _not_ be trusted at instantiation time. Relying in this
can be conformant to standard, but it is dangerous, because the
compiler, whenever it has to instantiate the template, is constructing
a type which contains as parameter not a proper value, but instead
something like a "slot" to be filled in later. Someone might forget
this, and try to make, for example, a template specialization, as I
suggested in my previous post.
Let's consider a real life example: The specialization might test
whether the pointer belongs or not to an specific memory arena. Now
the compiler is obliged to consider that value, and unexpected and
awful errors will occur, without the compiler giving a hint!.
Am I wrong?....
-= Ed =-
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Fri, 25 Jan 2002 18:42:27 GMT Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
[snipped]
>
>
> Is it legal?
Yes. See other postings.
> How can I use the address of a external variable as a template parameter.
> I mean, it is unknown at compile time, isn't it?
Look at the compiled code to see how your compiler handles it. In the case
of MSVC6, here's the decorated name for Int_A::val():
?val@?$A@H$1?global@@3HA@@SAHXZ
which undecorates to:
public: static int __cdecl A<int,&int global>::val(void); // not a valid
C++ declaration
Notice that the compiler simply used the name of the global whose address
was taken in naming the routine. Therefore, it didn't need to know the
address in order to produce the translation units.
Within the instantiation the compiler generated (note that I had to change
the name of the template parameter from val to ptr - otherwise there's two
val's visible: the name of the function itself and the template parameter,
and VC didn't like that):
; 5 : static T val() { return *ptr ; }
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 a1 00 00 00 00 mov eax, DWORD PTR ?global@@3HA ; global
00008 5d pop ebp
00009 c3 ret 0
It simply returned the value of the global variable on which it was
instantiated.
There are probably other ways a compiler could handle this, but VC's
strategy seems like the obvious solution to me.
-cd
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Fri, 25 Jan 2002 19:42:16 GMT Raw View
Carl Daniel <cpdaniel@pacbell.net> escribi=F3 en el mensaje de noticias
M1h48.36237$Cc2.2416047242@newssvr21.news.prodigy.com...
> "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
> [snipped]
> >
> >
> > Is it legal?
>
> Yes. See other postings.
>
> > How can I use the address of a external variable as a template
parameter.
> > I mean, it is unknown at compile time, isn't it?
>
> Look at the compiled code to see how your compiler handles it. In the
case
> of MSVC6, here's the decorated name for Int_A::val():
>
> ?val@?$A@H$1?global@@3HA@@SAHXZ
>
> which undecorates to:
>
> public: static int __cdecl A<int,&int global>::val(void); // not a va=
lid
> C++ declaration
>
> Notice that the compiler simply used the name of the global whose addre=
ss
> was taken in naming the routine. Therefore, it didn't need to know the
> address in order to produce the translation units.
>
> Within the instantiation the compiler generated (note that I had to cha=
nge
> the name of the template parameter from val to ptr - otherwise there's =
two
> val's visible: the name of the function itself and the template paramet=
er,
> and VC didn't like that):
>
> ; 5 : static T val() { return *ptr ; }
>
> 00000 55 push ebp
> 00001 8b ec mov ebp, esp
> 00003 a1 00 00 00 00 mov eax, DWORD PTR ?global@@3HA ; global
> 00008 5d pop ebp
> 00009 c3 ret 0
>
> It simply returned the value of the global variable on which it was
> instantiated.
>
> There are probably other ways a compiler could handle this, but VC's
> strategy seems like the obvious solution to me.
>
> -cd
>
>
I see.
But my surprise came not from the way the compiler translated val() but f=
rom
the fact that it uses
an unknown (at compile-time) value to generate the complete type
instantiated by the specialization.
That is, the typical answer to the question: why do non-type template
parameters require a constant expression? is that the compiler must know =
at
compile time which number to use to make a complete type.
I think that the question would have been more clear if I didn't included
val(), just the non-type template parameter.
Anyway, Eduardo shown that the compiler must be using a sort of fixup to
generate to instantiation, so the template matching mechanism
(specialization) might get into trouble, for instance, across different
translation units.
Thanks,
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Fri, 25 Jan 2002 20:44:30 GMT Raw View
Eduardo Alberto M C <eduardomadrid@hotmail.com> escribi=F3 en el mensaje =
de
noticias 73050ec6.0201250949.2c19c14e@posting.google.com...
> "Anthony Williams"<anthwil@nortelnetworks.com> wrote in message
news:<a2rahd$cqs$1@bcarh8ab.ca.nortel.com>...
> > "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> > news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
> > > Consider the following:
> >
> > > template<class T, T* val>
> > > struct A
> > > {
> > > static T val() { return *val ; }
> > > } ;
> > >
> > > extern int global ;
> > > typedef A<int,&global> Int_A ;
> >
> > > int main()
> > > {
> > > int v =3D Int_A::val();
> > > }
> >
> > > source_B.cpp
> > > ~~~~~~~~~~
> > > int global =3D 3 ;
> > >
> > >
> > > Is it legal?
> > > How can I use the address of a external variable as a template
parameter.
> > > I mean, it is unknown at compile time, isn't it?
> >
> > > The trick I've used seems to work as far as Borland is concerned, b=
ut
it
> > is
> > > portable?
> >
> > Yes.
> >
> > Global variables are required to have the same address when accessed
from
> > all translation units (otherwise they're not global). Also, two
unrelated
> > objects may not have the same address. Therefore the compiler knows t=
hat
> > &global must be a single address across all translation units, and ca=
n
emit
> > code that assumes this, and makes the linker determine the precise va=
lue
> > where needed.
> >
>
> That's true, however, better be careful. It is the *LINKER* who
> puts the right value _inside_ the templates, therefore, the value of
> &global _can_ _not_ be trusted at instantiation time. Relying in this
> can be conformant to standard, but it is dangerous, because the
> compiler, whenever it has to instantiate the template, is constructing
> a type which contains as parameter not a proper value, but instead
> something like a "slot" to be filled in later. Someone might forget
> this, and try to make, for example, a template specialization, as I
> suggested in my previous post.
>
> Let's consider a real life example: The specialization might test
> whether the pointer belongs or not to an specific memory arena. Now
> the compiler is obliged to consider that value, and unexpected and
> awful errors will occur, without the compiler giving a hint!.
>
> Am I wrong?....
>
Hi!
I just realized that the subject for my message coincided with some older
post, and since my viewer is configured to collapse by subject, I couldn'=
t
see my post nor all the answers until now.
Thanks to all who replied!
I agree with Ed here, though I also note that in the particular cases whe=
n
you use the technique knowing in advance the inherent potential problems
shown by him, it is safe. Of course, it requires proper documentation.
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Fri, 25 Jan 2002 21:40:06 GMT Raw View
Carl Daniel <cpdaniel@pacbell.net> escribi=F3 en el mensaje de noticias
M1h48.36237$Cc2.2416047242@newssvr21.news.prodigy.com...
> "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> news:a2po5h$12ojhd$1@ID-44132.news.dfncis.de...
> [snipped]
> >
> >
> > Is it legal?
>
> Yes. See other postings.
>
> > How can I use the address of a external variable as a template
parameter.
> > I mean, it is unknown at compile time, isn't it?
>
> Look at the compiled code to see how your compiler handles it. In the
case
> of MSVC6, here's the decorated name for Int_A::val():
>
> ?val@?$A@H$1?global@@3HA@@SAHXZ
>
> which undecorates to:
>
> public: static int __cdecl A<int,&int global>::val(void); // not a va=
lid
> C++ declaration
>
> Notice that the compiler simply used the name of the global whose addre=
ss
> was taken in naming the routine. Therefore, it didn't need to know the
> address in order to produce the translation units.
>
> Within the instantiation the compiler generated (note that I had to cha=
nge
> the name of the template parameter from val to ptr - otherwise there's =
two
> val's visible: the name of the function itself and the template paramet=
er,
> and VC didn't like that):
>
> ; 5 : static T val() { return *ptr ; }
>
> 00000 55 push ebp
> 00001 8b ec mov ebp, esp
> 00003 a1 00 00 00 00 mov eax, DWORD PTR ?global@@3HA ; global
> 00008 5d pop ebp
> 00009 c3 ret 0
>
> It simply returned the value of the global variable on which it was
> instantiated.
>
> There are probably other ways a compiler could handle this, but VC's
> strategy seems like the obvious solution to me.
>
> -cd
>
>
I see.
But my surprise came not from the way the compiler translated val() but f=
rom
the fact that it uses
an unknown (at compile-time) value to generate the complete type
instantiated by the specialization.
That is, the typical answer to the question: why do non-type template
parameters require a constant expression? is that the compiler must know =
at
compile time which number to use to make a complete type.
I think that the question would have been more clear if I didn't included
val(), just the non-type template parameter.
Anyway, Eduardo shown that the compiler must be using a sort of fixup to
generate to instantiation, so the template matching mechanism
(specialization) might get into trouble, for instance, across different
translation units.
Thanks,
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Fri, 25 Jan 2002 21:44:45 GMT Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a2sc8q$13plp1$1@ID-44132.news.dfncis.de...
>Anyway, Eduardo shown that the compiler must be using a sort of fixup to
>generate to instantiation, so the template matching mechanism
>(specialization) might get into trouble, for instance, across different
>translation units.
There's nothing to worry about - the compiler is required to get it right.
In the case of VC, for example, it simply uses the name of the global
variable as part of the name of the template instantiation. Since the
global variable must have the same name everywhere it's declared, the
instantiations will always be "in-sync" across different translation units.
Note that "pointer to int" is NOT a valid non-type template parameter in
general. Rather, "pointer to named global int" is a valid non-type template
parameter (or, in general, "pointer to thing with external linkage" is a
valid non-type template parameter).
If any compiler/linker gets this wrong across multiple translation units,
it's simply broken.
-cd
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Fri, 25 Jan 2002 22:25:49 GMT Raw View
Carl Daniel <cpdaniel@pacbell.net> escribi=F3 en el mensaje de noticias
Woj48.36568$NK1.2446766276@newssvr21.news.prodigy.com...
> "Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
> news:a2sc8q$13plp1$1@ID-44132.news.dfncis.de...
> >Anyway, Eduardo shown that the compiler must be using a sort of fixup =
to
> >generate to instantiation, so the template matching mechanism
> >(specialization) might get into trouble, for instance, across differen=
t
> >translation units.
>
> There's nothing to worry about - the compiler is required to get it rig=
ht.
> In the case of VC, for example, it simply uses the name of the global
> variable as part of the name of the template instantiation. Since the
> global variable must have the same name everywhere it's declared, the
> instantiations will always be "in-sync" across different translation
units.
>
> Note that "pointer to int" is NOT a valid non-type template parameter i=
n
> general. Rather, "pointer to named global int" is a valid non-type
template
> parameter (or, in general, "pointer to thing with external linkage" is =
a
> valid non-type template parameter).
>
> If any compiler/linker gets this wrong across multiple translation unit=
s,
> it's simply broken.
>
I see. Sounds reasonable.
Now that I think about it, the address of an object with external linkage=
is
a "constant expression" after all, even if it is unknown, because being
external is required to be the same across translation units.
So I can't think of any problem except the very particular of assuming so=
me
concrete property of this address, which is the specific problem shown by
Eduardo.
Thanks again,
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Sun, 27 Jan 2002 01:32:20 GMT Raw View
"Fernando Cacciola" <fcacciola@gosierra.com> wrote in message
news:a2skne$13t6jm$1@ID-44132.news.dfncis.de...
>Carl Daniel <cpdaniel@pacbell.net> escribi en el mensaje de noticias
>>
>> If any compiler/linker gets this wrong across multiple translation units,
>> it's simply broken.
>>
>I see. Sounds reasonable.
>Now that I think about it, the address of an object with external linkage
is
>a "constant expression" after all, even if it is unknown, because being
>external is required to be the same across translation units.
>
>So I can't think of any problem except the very particular of assuming some
>concrete property of this address, which is the specific problem shown by
>Eduardo.
>
I'm not certain that the concern Eduardo raised is valid. The pointer value
which is used as the non-type template parameter does have certain
properties, and since the template will be instantiated with that actual
value "burned into" the code (by the linker), it will always see a correct
value.
If you somehow (platform/implementation specfic) create a global with
external linkage in a special memory region (for example, using #pragma
Dataseg in MSVC), the template could test it's non-type template parameter's
value and determine, correctly, that it was within that special region.
Separate instantiations of the template on globals that both were and were
not in that special region would be guaranteed to see the correct values of
their parameters.
One thing the compiler couldn't do is make any assumptions at compile time.
Even though the pointer value is a constant, it's a constant unknown to the
compiler, so it'd have to generate code to evaluate expressions which would
otherwise be compile-time evaluated.
I suppose that could lead to some interesting impossibilities (or maybe
they're possible - it might be worth trying to find out what various
compilers do! and/or digging into the Standard to see what it says - maybe
tomorrow :-)
Consider:
template <bool> struct X {};
template <class T, T* p> struct Y
{
void f()
{
X<p & 1> x; // legal? possible?
}
};
-cd
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Steve Clamage <clamage@eng.sun.com>
Date: Sun, 27 Jan 2002 01:33:57 GMT Raw View
On Fri, 25 Jan 2002, Fernando Cacciola wrote:
>
> But my surprise came not from the way the compiler translated val() but from
> the fact that it uses
> an unknown (at compile-time) value to generate the complete type
> instantiated by the specialization.
>
> That is, the typical answer to the question: why do non-type template
> parameters require a constant expression? is that the compiler must know at
> compile time which number to use to make a complete type.
>
> Anyway, Eduardo shown that the compiler must be using a sort of fixup to
> generate to instantiation, so the template matching mechanism
> (specialization) might get into trouble, for instance, across different
> translation units.
I didn't see any possible problem that could arise, given the
usual implementation techniques.
A template having a non-type parameter T* can be instantiated only
on the address of an entity whose name has external linkage. By
definition, all uses of that global name anywhere in the entire
program refer to the same entity.
The compiler can therefore use the spelling of that name in
constructing the mangled name of template-related entities
(the name of the type, the qualifier of members, etc.).
The compiler does not need to use the as-yet unknown actual
address for any compile-time operation I can think of. That is,
an address can be used in some constant-expressions, but in
constant-expressions that must be evaluated at compile time.
What do you think could go wrong?
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Steve Clamage <clamage@eng.sun.com>
Date: Sun, 27 Jan 2002 17:09:11 GMT Raw View
Gremlins removed a "not" from the next-to-last sentence. Sigh.
--
Steve Clamage, stephen.clamage@sun.com
On Sun, 27 Jan 2002, Steve Clamage wrote:
>
> On Fri, 25 Jan 2002, Fernando Cacciola wrote:
> >
> > But my surprise came not from the way the compiler translated val() but from
> > the fact that it uses
> > an unknown (at compile-time) value to generate the complete type
> > instantiated by the specialization.
> >
> > That is, the typical answer to the question: why do non-type template
> > parameters require a constant expression? is that the compiler must know at
> > compile time which number to use to make a complete type.
> >
> > Anyway, Eduardo shown that the compiler must be using a sort of fixup to
> > generate to instantiation, so the template matching mechanism
> > (specialization) might get into trouble, for instance, across different
> > translation units.
>
> I didn't see any possible problem that could arise, given the
> usual implementation techniques.
>
> A template having a non-type parameter T* can be instantiated only
> on the address of an entity whose name has external linkage. By
> definition, all uses of that global name anywhere in the entire
> program refer to the same entity.
>
> The compiler can therefore use the spelling of that name in
> constructing the mangled name of template-related entities
> (the name of the type, the qualifier of members, etc.).
>
> The compiler does not need to use the as-yet unknown actual
> address for any compile-time operation I can think of. That is,
> an address can be used in some constant-expressions, but in
^not
> constant-expressions that must be evaluated at compile time.
>
> What do you think could go wrong?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Mon, 28 Jan 2002 18:29:55 GMT Raw View
"Carl Daniel" <cpdaniel@pacbell.net> wrote in message
news:zFs48.36901$n66.2595776626@newssvr21.news.prodigy.com...
> One thing the compiler couldn't do is make any assumptions at compile
time.
> Even though the pointer value is a constant, it's a constant unknown to
the
> compiler, so it'd have to generate code to evaluate expressions which
would
> otherwise be compile-time evaluated.
>
> I suppose that could lead to some interesting impossibilities (or maybe
> they're possible - it might be worth trying to find out what various
> compilers do! and/or digging into the Standard to see what it says -
maybe
> tomorrow :-)
>
> Consider:
>
> template <bool> struct X {};
>
> template <class T, T* p> struct Y
> {
> void f()
> {
> X<p & 1> x; // legal? possible?
> }
> };
This isn't legal.
14.3.2/1 states that a non-type template parameter must be an integral
constant-expression, a non-type template parameter, an object or function
with external linkage or a member-pointer. Clearly, if it is any of these
it is the first. Constant-expressions are defined in 5.19, and integral
constant-expressions are defined in 5.19/1, and are only allowed to "involve
literals, enumerators, const variables or static data members of integral or
enumeration types, and sizeof expressions." (And, in certain cases, floating
literals.) The variable p is none of these, and so is not allowed in a
integral constant-expression.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Fernando Cacciola" <fcacciola@gosierra.com>
Date: Thu, 24 Jan 2002 13:47:29 CST Raw View
Hi all!
Consider the following:
header.hpp
~~~~~~~
template<class T, T* val>
struct A
{
static T val() { return *val ; }
} ;
extern int global ;
typedef A<int,&global> Int_A ;
source_A.cpp
~~~~~~~~~~
int main()
{
int v = Int_A::val();
}
source_B.cpp
~~~~~~~~~~
int global = 3 ;
Is it legal?
How can I use the address of a external variable as a template parameter.
I mean, it is unknown at compile time, isn't it?
However, I could compile it and it run as expected with Borland 5.5.1.
I'm surprised that it worked...
In case you wonder, what I tried to do is to mimic the behaviour of a static
data member, intended to
be a unique shared global resource, in a template class.
That is, unless I'm missing something, if template class A would be defined
like this:
template<class T>
struct A
{
static T v ;
} ;
then depending on when, where, and how I instantiate A<xxx>, multiple
different copies of A::v would eventually
exist, defeating the purpose of A::v being a shared global resource.
The trick I've used seems to work as far as Borland is concerned, but it is
portable?
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
--
Fernando Cacciola
Sierra s.r.l.
fcacciola@gosierra.com
www.gosierra.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: pdimov@mmltd.net (Peter Dimov)
Date: Sun, 14 Oct 2001 22:09:06 GMT Raw View
Is the following program legal? Comeau seems to like it, but g++
2.95.2 and Borland 5.5.1 complain.
template<class R, class F> struct bind_t {};
template<class R> bind_t<R, R (*) ()> bind(R (*f) ());
template<class R, class F> bind_t<R, F> bind(F f);
template<class F> bind_t<typename F::result_type, F> bind(F f);
void g();
struct G
{
typedef void result_type;
};
struct H
{
};
int main()
{
bind(g);
bind(G());
bind<void>(H());
}
--
Peter Dimov
Multi Media Ltd.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Mon, 15 Oct 2001 17:45:41 GMT Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0110110325.5d483044@posting.google.com...
> Is the following program legal? Comeau seems to like it, but g++
> 2.95.2 and Borland 5.5.1 complain.
>
> template<class R, class F> struct bind_t {};
>
> template<class R> bind_t<R, R (*) ()> bind(R (*f) ());
>
> template<class R, class F> bind_t<R, F> bind(F f);
>
> template<class F> bind_t<typename F::result_type, F> bind(F f);
>
> void g();
>
> struct G
> {
> typedef void result_type;
> };
>
> struct H
> {
> };
>
> int main()
> {
> bind(g); // A
> bind(G()); // B
> bind<void>(H()); // C
> }
Cases A and C are an resounding "Yes", IMO.
Case B requires more thought. Can the third function template be considered
"more specialized" than the second? IMO it can, as the single template
parameter F of the third template can always be deduced from the arguments
to the second, but the template argument R of the second template can never
be deduced from the arguments.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Mon, 15 Oct 2001 17:47:02 GMT Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0110110325.5d483044@posting.google.com...
> Is the following program legal? Comeau seems to like it, but g++
> 2.95.2 and Borland 5.5.1 complain.
The program below would be well-formed had you supplied definitions for the
functions and function templates that were used therein. For the rest it is
legal.
> template<class R, class F> struct bind_t {};
>
> template<class R> bind_t<R, R (*) ()> bind(R (*f) ()); // 1
>
> template<class R, class F> bind_t<R, F> bind(F f); // 2
>
> template<class F> bind_t<typename F::result_type, F> bind(F f); // 3
>
> void g();
>
> struct G
> {
> typedef void result_type;
> };
>
> struct H
> {
> };
>
> int main()
> {
For the call bellow template argument deduction succeeds only for the
function template which I marked 1. For the function template 3, template
argument deduction results in an invalid type, as described in 14.8.2/2,
which means that its corresponding specialization is not included in the set
of candidate functions submitted to overload resolution. See 14.8.2/4.
> bind(g);
The set of candidate functions comprises only the specialization
'bind_t<void,G> bind(G)' of the function template 3.
> bind(G());
Template argument deduction succeeds only for the function template 2. While
for the function template 3 it fails for reasons similar to those explained
two paragraphs above.
> bind<void>(H());
> }
Regards,
Andrei Iltchenko.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Mon, 15 Oct 2001 22:43:21 GMT Raw View
"Anthony Williams" <anthwil@nortelnetworks.com> wrote in message
news:9qe5gm$nkovc$1@ID-49767.news.dfncis.de...
> "Peter Dimov" <pdimov@mmltd.net> wrote in message
> news:7dc3b1ea.0110110325.5d483044@posting.google.com...
> > Is the following program legal? Comeau seems to like it, but g++
> > 2.95.2 and Borland 5.5.1 complain.
> >
> > template<class R, class F> struct bind_t {};
> >
> > template<class R> bind_t<R, R (*) ()> bind(R (*f) ());
> >
> > template<class R, class F> bind_t<R, F> bind(F f);
> >
> > template<class F> bind_t<typename F::result_type, F> bind(F f);
> >
> > void g();
> >
> > struct G
> > {
> > typedef void result_type;
> > };
> >
> > struct H
> > {
> > };
> >
> > int main()
> > {
> > bind(g); // A
> > bind(G()); // B
> > bind<void>(H()); // C
> > }
>
> Case B requires more thought. Can the third function template be
considered
> "more specialized" than the second?
Maybe it can, but in the case of this example it is irrelevant. The second
function template has two template parameters, only one of which can be
deduced from a function call. As the first template parameter is not
explicitly specified in the function call expression 'bind(G())', template
argument deduction fails for the second function template, meaning that it
contributes no specializations to the set of candidate functions supplied to
overload resolution.
> IMO it can, as the single template
> parameter F of the third template can always be deduced from the arguments
> to the second, but the template argument R of the second template can
never
> be deduced from the arguments.
Regards,
Andrei Iltchenko.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: scott douglass <sdouglass%_%junk@_.arm.com>
Date: 1998/05/02 Raw View
Jay Zipnick wrote:
>
> Are each of the declarations below legal according to the standard? There
> are five different declarations:
I'll give it a shot:
Most of them are illegal because section 7.2 (Nov 1996 draft) says:
3 In a simple-declaration, the optional init-declarator-list can be
omitted only when declaring a class or enumeration,
that is, when the decl-specifier-seq contains either a
class-specifier, an elaborated-type-specifier with a class-key,
or an enum-specifier. In these cases and whenever a
class-specifier or enum-specifier is present in the decl-specifier-
seq, the identifiers in these specifiers are among the names being
declared by the declaration (as class-names, enum-names, or enumera-
tors, depending on the syntax). In such cases, and except for the
declaration of an unnamed bit-field, the decl-specified-
seq shall introduce one or more names into the program, or shall rede-
clare a name introduced by a previous declaration. [Example:
enum { }; // ill-formed
typedef class { }; // ill-formed
--end example]
The last sentence before the example prohibits "such cases" (i.e.
omiting the init-declarator-list) unless the "decl-specified-seq"[*],
which must contain "either a class-specifier, an
elaborated-type-specifier with a class-key, or an enum-specifier",
introduces or redeclares a name. I don't believe that member names
inside the class-specifier count as names being introduced by the
declaration[**].
This invalidates TEST1, TEST2, TEST4 and TEST5.
I don't see any problem with TEST3. Why do you suspect it is illegal?
[*] must be a typo in the draft; should be "decl-specifier-seq"
[**] except I have to allow anonymous unions, hmmm.... the wording could
be better
>//--------------- TEST1 ---------------
>// Unnamed struct with array
>struct { int a[1]; };
>
>
>//--------------- TEST2 ---------------
>// Two unnamed structs with array, both within a struct
>// Note both unnamed structs have the same identifier "a"
>struct b
> {
> struct { int a[1]; };
> struct { int a[1]; };
> };
>
>
>//--------------- TEST3 ---------------
>// Zero width unnamed bit-field in a struct with no members
>// (see section 9.6 paragraph 2)
>struct c { : 0; };
>
>
>//--------------- TEST4 ---------------
>// Zero width unnamed bit-field in an unnamed struct
>struct { : 0; };
>
>
>//--------------- TEST5 ---------------
>// Zero width unnamed bit-field in an unnamed struct, in a struct
>struct d
> {
> struct { : 0; };
> };
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: no_junk_mail@best.com (Jay Zipnick)
Date: 1998/04/28 Raw View
Are each of the declarations below legal according to the standard? There
are five different declarations:
//--------------- TEST1 ---------------
// Unnamed struct with array
struct { int a[1]; };
//--------------- TEST2 ---------------
// Two unnamed structs with array, both within a struct
// Note both unnamed structs have the same identifier "a"
struct b
{
struct { int a[1]; };
struct { int a[1]; };
};
//--------------- TEST3 ---------------
// Zero width unnamed bit-field in a struct with no members
// (see section 9.6 paragraph 2)
struct c { : 0; };
//--------------- TEST4 ---------------
// Zero width unnamed bit-field in an unnamed struct
struct { : 0; };
//--------------- TEST5 ---------------
// Zero width unnamed bit-field in an unnamed struct, in a struct
struct d
{
struct { : 0; };
};
I am hoping for a definitive yes/no for each. I have yet to find any
wording in the standard that prohibits any of these.
Thanks,
Jay Zipnick
--
(Change usernaem from junkmail to jayz to reply)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: mlg@scr.siemens.com (Michael Greenberg)
Date: 1997/09/05 Raw View
Is this code fragment legal?
typedef struct mumble mumblexx;
struct mumblexx {
int i;
} ;
Thanks,
--
Michael Greenberg email: mgreenberg@scr.siemens.com
Siemens Corporate Research phone: 609-734-3347
755 College Road East fax: 609-734-6565
Princeton, NJ 08540
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Steve Clamage <stephen.clamage_nospam@Eng.Sun.COM>
Date: 1997/09/08 Raw View
Michael Greenberg wrote:
>=20
> Is this code fragment legal?
>=20
> typedef struct mumble mumblexx;
>=20
> struct mumblexx {
> int i;
> } ;
>=20
No. From section 7.1.3 "The typedef specifier":
"A typedef=ADname that names a class is a class=ADname. The
typedef-name shall not be used after a class, struct, or
union prefix and not in the names for constructors and
destructors within the class declaration itself."
--=20
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: rice@tiac.net (Ken Rice)
Date: 1996/02/26 Raw View
template < class ItemType > class T
{
public:
T(){}
virtual ~T(){}
ItemType mArr;
};
void main(void)
{
T<int>* pA = nil;
dynamic_cast < T<int>* > (pA);
}
Our compiler reports this error:
Error : illegal use of incomplete struct/union/class
x.cp line 12 dynamic_cast < T<int>* > (pA);
Note that T<int> is not used in a way that causes it to be instantiated until
it gets to the dynamic_cast. The april 95 draft sec 5.2.6 [expr.dynamic.cast]
says "Types shall not be defined in a dynamic_cast."
So, the question is, does using a template that has not been instantiated
before count as 'defining a type' (as the compiler seems to think), or is
the code legal?
The example can be made to compile by gratuitously declaring a variable of
type T<int> before the dynamic_cast line to force implicit instantiation,
but that seems a bit kludgy.
Thanks,
Ken Rice.
--
Ken Rice
rice@tiac.net
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: tblancha@evolving.com (Todd Blanchard)
Date: 1995/07/03 Raw View
J. Stephen Adamczyk (jsa@edg.com) wrote:
: the name AFunction is ambiguous in the derived class,
: and any use of it will draw an error.
: With namespaces, it is possible to explicitly draw the two functions
: into the derived class:
: class D : public A<B>, public A<C> {
: using A<B>::AFunction;
: using A<C>::AFunction;
: };
: This overloads the functions in the derived class. Of course, not many
: compilers implement namespaces at this time.
Yes, but this is no better than:
class D : public A<B>, public A<C>
{
void AFunction(const B& b) { A<B>::AFunction(b); }
void AFunction(const C& c) { A<C>::AFunction(c); }
};
And with lots of MI, the stitchery required to make the compiler happy
(if it really tried, it could figure out what to do) is excessive.
This nonsense is the best reason I've seen yet to adopt Soukup's pattern
class style. Of course, I managed to work around the compiler's attitude with
the following:
template <class T> class A
{
friend A<T>& operator += (A<T>&, const T&);
// the real function I needed anyhow
};
template <class T> A<T>& operator += (A<T>&, const T&);
But this doesn't work well for functions, and you can't do assignment (has to
be a member - also needlessly restrictive).
This sort of foolishness makes C++ a *much* less than satisfying language.
Todd Blanchard
Author: jsa@edg.com (J. Stephen Adamczyk)
Date: 1995/06/30 Raw View
In article <3ssad4$2ii@citadel.evolving.com> tblancha@evolving.com (Todd Blanchard) writes:
>Here's an annoyance I'm running into. Its along the lines of the
>"function void foo() hides int foo()" variety.
>
>template <class T> class A { public: void AFunction(const T&); };
>class B;
>class C;
>class D : public A<B>, public A<C> { ... };
> B b;
> C c;
> D d;
> d.AFunction(b); // should call A<B>::AFunction
> d.AFunction(c); // should call A<C>::AFunction
>
>Instead I get a compiler error that says it can't tell what version of
>AFunction to call. I don't see the ambiguity. What's the official reason
>for this behavior? Is it legal?
In the pre-namespace C++ language, it's never possible to get functions
from different scopes or classes into an overload set. That is, all
functions in an overload set must be (direct) members of the same class,
or declared in the same scope.
For the above to work the way you want, the function from A<B> and the
one from A<C> would have to be in an overload set together. But they're
not; instead, the name AFunction is ambiguous in the derived class,
and any use of it will draw an error.
With namespaces, it is possible to explicitly draw the two functions
into the derived class:
class D : public A<B>, public A<C> {
using A<B>::AFunction;
using A<C>::AFunction;
};
This overloads the functions in the derived class. Of course, not many
compilers implement namespaces at this time.
Steve Adamczyk
Edison Design Group
Author: tblancha@evolving.com (Todd Blanchard)
Date: 1995/06/28 Raw View
Here's an annoyance I'm running into. Its along the lines of the
"function void foo() hides int foo()" variety.
consider:
template <class T> class A { public: void AFunction(const T&); };
class B;
class C;
class D : public A<B>, public A<C> { ... };
B b;
C c;
D d;
d.AFunction(b); // should call A<B>::AFunction
d.AFunction(c); // should call A<C>::AFunction
Instead I get a compiler error that says it can't tell what version of
AFunction to call. I don't see the ambiguity. What's the official reason
for this behavior? Is it legal? And will Batman escape from Mr Freeze's
giant snowcone machine?
Todd Blanchard
Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 #71425)
Date: 28 Sep 1994 18:37:44 GMT Raw View
In article <36bbvc$m27@rzsun02.rrz.uni-hamburg.de>
admin@rzaix319.uni-hamburg.de (Bernd Eggink) writes:
|> John Andrew Fingerhut (jaf3@ritz.cec.wustl.edu) wrote:
|> : Is it legal to initialize a member pointer in the parameter list of a
|> : base class ctor?
|> : class mybuf;
|> : class mystream : public ostream {
|> : mybuf *buf;
|> : public:
|> : mystream () : ostream (buf = new mybuf) { }// buf is member of mystream
|> : ~mystream () { delete buf; }
|> : };
|> : Stephen Gevers
|> : sg3235@shelob.sbc.com
|> It's at least bad style and possibly not portable. A member should not be
|> assigned to before base class initialization. You can avoid it by adding
|> a base class which contains the buffer pointer:
|> class mybuf { /* ... */ };
|> class makebuf
|> { public:
|> makebuf(): buf(new mybuf) { }
|> mybuf *buf;
|> };
|> class mystream: public makebuf, public ostream
|> { public:
|> mystream(): ostream(buf) { }
|> // ...
|> };
|> The makebuf constructor is called before the ostream constructor,
|> so everythings gets initialized in the proper sequence.
I didn't respond, since I wasn't sure of the answer. But since the
John Fingerhut started so well, I will suggest several alternatives:
There are two obvious solutions, differing only in the implementation
of the constructor. (The following supposes Stephen Gevers
declaration.)
mystream::mystream()
: ostream( new mybuf )
, buf( (mybuf*)rdbuf() )
{
}
and
mystream::mystream()
: buf( new mybuf )
{
init( buf ) ;
}
Given the definition of `init' in ios, I suspect that the originators
of iostream had the latter in mind.
Still, I like the idea of solving the problem with an additional
class. In this case, however, I would add a level of inheritance,
rather than using multiple inheritance:
class mystream_init : public ostream
{
protected :
mystream_init( mybuf* buf ) ;
mybuf* theBuffer ;
} ;
mystream_init::mystream_init( mybuf* buf )
: ostream( buf )
, theBuffer( buf )
{
}
class mystream : public mystream_init
{
public :
mystream() ;
} ;
mystream::mystream()
: mystream_init( new mybuf )
{
}
Given that the authors of iostream have already provided for another
solution, I think that I would use it and not be bothered. But the
idea is interesting for similar cases, where the base class authors
have not been so prevoyant.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: jaf3@ritz.cec.wustl.edu (John Andrew Fingerhut)
Date: 26 Sep 1994 14:52:33 -0500 Raw View
Is it legal to initialize a member pointer in the parameter list of a
base class ctor?
class mybuf;
class mystream : public ostream {
mybuf *buf;
public:
mystream () : ostream (buf = new mybuf) { }// buf is member of mystream
~mystream () { delete buf; }
};
Stephen Gevers
sg3235@shelob.sbc.com
Author: pjl@graceland.att.com (Paul J. Lucas)
Date: Tue, 27 Sep 1994 12:38:30 GMT Raw View
In <3678q1$r0i@ritz.cec.wustl.edu> jaf3@ritz.cec.wustl.edu (John Andrew Fingerhut) writes:
>Is it legal to initialize a member pointer in the parameter list of a
>base class ctor?
>class mybuf;
>class mystream : public ostream {
> mybuf *buf;
>public:
> mystream () : ostream (buf = new mybuf) { }// buf is member of mystream
> ~mystream () { delete buf; }
>};
Certainly not like this: mybuf has not been seen.
--
- Paul J. Lucas
AT&T Bell Laboratories
Naperville, IL
Author: admin@rzaix319.uni-hamburg.de (Bernd Eggink)
Date: 28 Sep 1994 09:11:08 GMT Raw View
John Andrew Fingerhut (jaf3@ritz.cec.wustl.edu) wrote:
: Is it legal to initialize a member pointer in the parameter list of a
: base class ctor?
: class mybuf;
: class mystream : public ostream {
: mybuf *buf;
: public:
: mystream () : ostream (buf = new mybuf) { }// buf is member of mystream
: ~mystream () { delete buf; }
: };
: Stephen Gevers
: sg3235@shelob.sbc.com
It's at least bad style and possibly not portable. A member should not be
assigned to before base class initialization. You can avoid it by adding
a base class which contains the buffer pointer:
class mybuf { /* ... */ };
class makebuf
{ public:
makebuf(): buf(new mybuf) { }
mybuf *buf;
};
class mystream: public makebuf, public ostream
{ public:
mystream(): ostream(buf) { }
// ...
};
The makebuf constructor is called before the ostream constructor,
so everythings gets initialized in the proper sequence.
--
Bernd Eggink
Rechenzentrum Uni Hamburg
admin@rzaix13.rrz.uni-hamburg.de
Author: jamshid@ses.com (Jamshid Afshar)
Date: Mon, 6 Jun 1994 21:28:49 GMT Raw View
In article <2srri7$i8f@nova.umd.edu>, Ellster <COATES@UMUC.UMD.EDU> wrote:
>In <1994Jun1.041749.12010@news.uta.edu> kumar@news.uta.edu writes:
>
>> We faced a similar problem where we wanted to access a function of
>> derived class using a base class pointer.
>> One possible solution can be :
>>
>> #include<iostream.h>
>>
>> class test1{
>> public :
>> void try1(){ cout << "test1" <<endl;}
>>
>> };
>>
>> class test2 : public test1{
>> public:
>> void try1() { cout<< "test2"<< endl;}
>> };
>>
>> main() {
>> test1 *ptr;
>> test1 obj1;
>> test2 obj2;
>>
>> obj1.try1();
>> ptr = &obj1;
>> ptr->try1();
>> ptr = &obj2;
>> ((test2*) ptr)->try1();/* type casting of the base class
>> pointer to that of the derived class BUT not good for maintenance*/
>>
>> }
>>
>> results :
>> a.out
>> test1
>> test1
>> test2
>
>This is the result that ticks me off about C++. I mean, I could see if
>you had copied obj2 to obj1 and somehow obj2's 'try2()' method got sliced,
>but supposedly you're pointing to the class obj2 itself! From reading
>here it's seems that the compiler has tables which limit any call via
>'ptr' to obj1 since that's the type 'ptr' was created as.
I'm not sure what you mean, but the above output makes perfect sense
to me. When you call a member function on a pointer, the function
name is looked up in the class which is pointed to. `ptr->name()'
looks up "name" in the class test1 and `((test2*)ptr)->name()' looks
"name" in the class test2. If the function found is a virtual
function then the virtual call mechanism is used, meaning that the
object's most derived class's definition of the function will be
called. But if "name" is a non-virtual function, a simple member
function call is made. Of course, if `ptr' does not point to a test2
object or object derived from test2, then the cast and subsequent call
result in undefined behavior. But, the above code and output are
correct.
>Of course
>virtual would get around it but why should you have to do that in this
>circumstance!? It's seems only natural that if the address of 'prt1' is
>now obj2 then we should be able to activate obj2's methods without a cast.
>Making C++ behave as I suggest would go quite a way in making it more
>[efficient,] useful and enjoyable.
I don't understand what you mean, especially wrt the efficiency and
usability aspects. Unless you simply misunderstood the example, can
you repost an explanation?
Jamshid Afshar
jamshid@ses.com
Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 7 Jun 1994 02:51:48 GMT Raw View
>>>>> Ellster <COATES@UMUC.UMD.EDU> writes:
> Of course virtual would get around it but why should you have to do that
> in this circumstance!?
Because that is exactly the purpose of virtual functions.
Jason
Author: COATES@UMUC.UMD.EDU (Ellster)
Date: 5 Jun 1994 06:32:39 GMT Raw View
In <1994Jun1.041749.12010@news.uta.edu> kumar@news.uta.edu writes:
> We faced a similar problem where we wanted to access a function of
> derived class using a base class pointer.
>
>
> One possible solution can be :
>
> #include<iostream.h>
>
> class test1{
> public :
> void try1(){ cout << "test1" <<endl;}
>
> };
>
> class test2 : public test1{
>
> public:
> void try1() { cout<< "test2"<< endl;}
> };
>
>
> main()
> {
> test1 *ptr;
> test1 obj1;
> test2 obj2;
>
> obj1.try1();
> ptr = &obj1;
> ptr->try1();
> ptr = &obj2;
> ((test2*) ptr)->try1();/* type casting of the base class
> pointer to that of the derived class BUT not good for maintenance*/
>
> }
>
> results :
> a.out
> test1
> test1
This is the result that ticks me off about C++. I mean, I could see if
you had copied obj2 to obj1 and somehow obj2's 'try2()' method got sliced,
but supposedly you're pointing to the class obj2 itself! From reading
here it's seems that the compiler has tables which limit any call via
'ptr' to obj1 since that's the type 'ptr' was created as. Of course
virtual would get around it but why should you have to do that in this
circumstance!? It's seems only natural that if the address of 'prt1' is
now obj2 then we should be able to activate obj2's methods without a cast.
Making C++ behave as I suggest would go quite a way in making it more
useful and enjoyable.
> test2
Author: COATES@UMUC.UMD.EDU (Ellster)
Date: 5 Jun 1994 06:39:36 GMT Raw View
> Making C++ behave as I suggest would go quite a way in making it more
> useful and enjoyable.
I'd like to change my statement to "more [efficient], useful and
enjoyable."
Author: thuerman@ibr.cs.tu-bs.de (Urs Thuermann)
Date: Fri, 27 May 1994 11:47:26 GMT Raw View
rad6938@tntech.edu (Rad) writes:
>In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
>werme@databrpc.chinalake.navy.mil (Todd Werme) writes:
>> Recently, I have seen code fragments is some C++ books regarding redefination of inherited
>> non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>>
>> Type of code fragment in question:
>>
>> class Base {
>> public:
>> void func() { do_stuff(); } // non-virtual function
>> ...
>> }
>>
>> class Derived: public Base {
>> public:
>> void func() { do_other_stuff(); }
>> ...
>> }
> According to the ARM functions can be redefined in a derived class.
>In order to access the function in the base class you must use the scope
>resolution operator. (ref. ARM sect. 10)
This is something I've just understood (I hope). If you don't declare
the function virtual no dispatch is done, i.e. if you have a pointer to
Base that really points to an object of class Derived and call the func,
the function of teh Base class is executed.
Derived d;
Base *p = &d;
p->func(); // This will call Base::func()
If you declare it virtual dispatching takes place.
Is this really true (it's at least what g++ seems to do).
But what if have
class B {
public:
virtual void f();
};
class D1 : public B {
public:
void f(); // is this virtual although not declared so
};
class D2 : public D1 {
public:
void f();
};
main()
{
D2 d2;
D1 *p = &d2;
p->f(); // g++ makes a dispatched call although
// D1::f() is not declared virtual
}
It seems that a function overriding a virtual function is vitual too,
even if not declared as such. Is that correct?
Urs
Author: agql@gmv.es (Agustin Gonzalez-Quel)
Date: Tue, 24 May 1994 15:44:19 GMT Raw View
Qi Deng (qi@rhino.ecn.purdue.edu) wrote:
: In article <Cq9KDI.FG8@borland.com> pete@genghis.interbase.borland.com (Pete Becker) writes:
: >In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
: >Todd Werme <werme@databrpc.chinalake.navy.mil> wrote:
: >>Hello,
: >>
: >>Recently, I have seen code fragments is some C++ books regarding redefination of inherited
: >>non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
: >>
: >>Type of code fragment in question:
: >>
: >>class Base {
: >> public:
: >> void func() { do_stuff(); } // non-virtual function
: >> ...
: >>}
: >>
: >>class Derived: public Base {
: >> public:
: >> void func() { do_other_stuff(); }
: >> ...
: >>}
: >>
: >
: > It is legal. The name in the derived class hides the name from the
: >base class.
: > -- Pete
: >
: >
: I doubt it, when we talk about virtual functions, we usually mean
: to access those functions from a pointer pointed to a base class,
: and if now this pointer points to a derived class object, we hope the
: virtual function of the derived class overrides that of the
: base class, look at my small sample program,
( Example deleted )
From your own example you are saying that it is a legal
construction that must be used when you don't want the 'virtual'
behaviour to appear. This is, when you want that the function executed
when you call it through a pointer to the base class is the function
defined in the base class, regardless if this pointer points at that
given moment to any object of a derived class with such a function
re-defined.
Regards,
Agustin
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Agustin Gonzalez-Quel Lombardo e-mail:agonzalez@gmv.es
FAX: 34-1-807 21 99
Address:
GMV S.A.
Isaac Newton s/n
PTM, Tres Cantos
28760 MADRID (SPAIN)
Telf: 34-1-807 21 87 / 34-1-807 21 00
__
\/ Este mensaje se transmite usando electrones 100% reciclados
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Author: werme@databrpc.chinalake.navy.mil (Todd Werme)
Date: Mon, 23 May 1994 14:02:09 GMT Raw View
Hello,
Recently, I have seen code fragments is some C++ books regarding redefination of inherited
non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
Type of code fragment in question:
class Base {
public:
void func() { do_stuff(); } // non-virtual function
...
}
class Derived: public Base {
public:
void func() { do_other_stuff(); }
...
}
Thanks for your help,
Todd Werme werme@databrpc.chinalake.navy.mil
If this is a stupid question, just ignore it. No flames please.
Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Mon, 23 May 1994 16:27:16 GMT Raw View
In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
Todd Werme <werme@databrpc.chinalake.navy.mil> wrote:
>Hello,
>
>Recently, I have seen code fragments is some C++ books regarding redefination of inherited
>non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>
>Type of code fragment in question:
>
>class Base {
> public:
> void func() { do_stuff(); } // non-virtual function
> ...
>}
>
>class Derived: public Base {
> public:
> void func() { do_other_stuff(); }
> ...
>}
>
It is legal. The name in the derived class hides the name from the
base class.
-- Pete
Author: rad6938@tntech.edu (Rad)
Date: 23 May 94 11:42:52 -0600 Raw View
In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
werme@databrpc.chinalake.navy.mil (Todd Werme) writes:
> Recently, I have seen code fragments is some C++ books regarding redefination of inherited
> non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>
> Type of code fragment in question:
>
> class Base {
> public:
> void func() { do_stuff(); } // non-virtual function
> ...
> }
>
> class Derived: public Base {
> public:
> void func() { do_other_stuff(); }
> ...
> }
According to the ARM functions can be redefined in a derived class.
In order to access the function in the base class you must use the scope
resolution operator. (ref. ARM sect. 10)
----------------------------------------------------------------------------
Richard Deken Graduate student in electrical engineering
Tennessee Technological University
Internet: rad6938@gemini.tntech.edu Cookeville, TN, USA
Author: qi@rhino.ecn.purdue.edu (Qi Deng)
Date: Mon, 23 May 1994 20:20:43 GMT Raw View
In article <Cq9KDI.FG8@borland.com> pete@genghis.interbase.borland.com (Pete Becker) writes:
>In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
>Todd Werme <werme@databrpc.chinalake.navy.mil> wrote:
>>Hello,
>>
>>Recently, I have seen code fragments is some C++ books regarding redefination of inherited
>>non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>>
>>Type of code fragment in question:
>>
>>class Base {
>> public:
>> void func() { do_stuff(); } // non-virtual function
>> ...
>>}
>>
>>class Derived: public Base {
>> public:
>> void func() { do_other_stuff(); }
>> ...
>>}
>>
>
> It is legal. The name in the derived class hides the name from the
>base class.
> -- Pete
>
>
I doubt it, when we talk about virtual functions, we usually mean
to access those functions from a pointer pointed to a base class,
and if now this pointer points to a derived class object, we hope the
virtual function of the derived class overrides that of the
base class, look at my small sample program,
#include <iostream.h>
class Base {
public:
void func() { cout<<"From Base with love...\n"<<flush; }
//func() is NOT virtual
};
class Derived: public Base {
public:
void func() { cout<<"From Derived with love...\n"<<flush; }
};
int
main()
{
Base *ptr;
Base base;
Derived derived;
base.func();
derived.func();
ptr=&base;
ptr->func();
ptr=&derived;
ptr->func();
return 0;
}
and it's output,
Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Mon, 23 May 1994 22:41:53 GMT Raw View
In article <Cq9v6K.6K4@noose.ecn.purdue.edu>,
Qi Deng <qi@rhino.ecn.purdue.edu> wrote:
>In article <Cq9KDI.FG8@borland.com> pete@genghis.interbase.borland.com (Pete Becker) writes:
>>In article <Cq9DnM.2z3@avalon.chinalake.navy.mil>,
>>Todd Werme <werme@databrpc.chinalake.navy.mil> wrote:
>>>Hello,
>>>
>>>Recently, I have seen code fragments is some C++ books regarding redefination of inherited
>>>non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>>>
>>>Type of code fragment in question:
>>>
>>>class Base {
>>> public:
>>> void func() { do_stuff(); } // non-virtual function
>>> ...
>>>}
>>>
>>>class Derived: public Base {
>>> public:
>>> void func() { do_other_stuff(); }
>>> ...
>>>}
>>>
>>
>> It is legal. The name in the derived class hides the name from the
>>base class.
>> -- Pete
>>
>>
>I doubt it, when we talk about virtual functions, we usually mean
>to access those functions from a pointer pointed to a base class,
>and if now this pointer points to a derived class object, we hope the
>virtual function of the derived class overrides that of the
>base class, look at my small sample program,
Please don't confuse things by changing the question then stating
that the answer is wrong! As written, the question is about non-virtual
functions and whether this construct is legal. It is, indeed legal. When you
make the function virtual it remains legal, but its behavior is different. The
virtual function in the derived class overrides the virtual function in the
base class, in addition to hiding its name.
When you call a non-virtual function through a pointer to a class, the
compiler looks at all the members of that class, including inherited members,
to determine whether there is a function with that name. It doesn't matter that
the actual object that the pointer points to is in fact of a class derived from
that class, and it doesn't matter what names that derived class uses for any
of its members. The compiler doesn't look at the derived class, only the base.
It calls the appropriate member function in the base class.
>
>#include <iostream.h>
>
>class Base {
> public:
> void func() { cout<<"From Base with love...\n"<<flush; }
> //func() is NOT virtual
>};
>
>class Derived: public Base {
> public:
> void func() { cout<<"From Derived with love...\n"<<flush; }
>};
>
>int
>main()
>{
> Base *ptr;
> Base base;
> Derived derived;
>
> base.func();
> derived.func();
>
> ptr=&base;
> ptr->func();
>
> ptr=&derived;
> ptr->func();
>
> return 0;
>}
>
>and it's output,
>
>From Base with love...
>From Derived with love...
>From Base with love...
>From Base with love...
>
>it's obvious that the derived's func didn't override the func
>of base if we accessed those func's by a pointer.
Yes, that's right. That's because the function isn't virtual.
>
>but if we change it to:
>//same
>
>class Base {
> public:
> virtual void func() { cout<<"From Base with love...\n"<<flush;
>}
> //func() IS virtual
>};
>
>//same
>
>the output,
>
>From Base with love...
>From Derived with love...
>From Base with love...
>From Derived with love...
>
>seems right.
>
Yes, that's because the function is virtual.
>I don't know what exactly legal or illegal mean here, but I know
>if I want my result correct, I got to use virtual.
Legal means that it is a valid construct in the language. If you want
virtual behavior then you must write virtual functions. In particular, if
you plan on accessing an object through a pointer to a base class, then you
must be sure that you've written it so that it works correctly.
The reason that it's good for the name in the derived class to hide
the same name in the base is that that means you don't have to stay out of the
way of the internals of the base class:
class Base
{
public:
void ShowBase() { cout << GetName() << endl; }
private:
const char *GetName() { return "Base"; }
};
class Derived : public Base
{
public:
void ShowDerived() { cout << GetName() << endl; }
private:
const char *GetName() { return "Derived"; }
};
Derived d;
d.ShowBase(); // displays 'Base'
d.ShowDerived(); // displays 'Derived'
-- Pete
Author: cameron@spri.levels.unisa.edu.au (Cameron Miller)
Date: 24 May 1994 00:26:59 GMT Raw View
Todd Werme (werme@databrpc.chinalake.navy.mil) wrote:
: Hello,
: Recently, I have seen code fragments is some C++ books regarding redefination of inherited
: non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
: Type of code fragment in question:
: class Base {
: public:
: void func() { do_stuff(); } // non-virtual function
: ...
: }
: class Derived: public Base {
: public:
: void func() { do_other_stuff(); }
: ...
: }
It's legal. Have a look at page 208 of the ARM. There is an example of similar
code on that page. Say we have
Base b;
Derived d;
b.func(); // calls Base::func()
d.func(); // calls Derived::func()
d.Base::func() // calls Base::func()
--
Cameron Miller
<cameron@spri.levels.unisa.edu.au>
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 24 May 1994 09:27:25 GMT Raw View
In article <Cq9DnM.2z3@avalon.chinalake.navy.mil> werme@databrpc.chinalake.navy.mil (Todd Werme) writes:
>Hello,
>
>Recently, I have seen code fragments is some C++ books regarding redefination of inherited
>non-virtual functions. Most books say this is illegal, some say it is legal. Which is it?
>
>Type of code fragment in question:
>
>class Base {
> public:
> void func() { do_stuff(); } // non-virtual function
>}
>
>class Derived: public Base {
> public:
> void func() { do_other_stuff(); }
>}
Its legal. The function in the derived class HIDES
that of the base because it has the same name. This is
true irrespective of its signature or whether it is virtual.
The base class function may still be called using the scope
override operator:
Derived::a_method() { .. Base::func(); .. }
or through a pointer or reference to the base
base_pointer->func()
but this latter case will dispatch to an overriding virtual (which must
has the same signature) if the base function had been virtual.
>
>Thanks for your help,
>If this is a stupid question, just ignore it. No flames please.
I thought your question very well put and more concise
than many of mine. Knowing that this sort of thing is confusing
is not unimportant for the Standardisation forum which
comp.std.c++ is.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA