Topic: Compiler diffs
Author: "Balog Pal" <pasa@lib.hu>
Date: Thu, 13 Dec 2001 15:53:06 CST Raw View
I'm porting a set of code from under MSVC to a g++/linux and experience interesting differences.
I want to know if what I observe is a bug in either compiler or what. :)
Diff 1. ptm
struct foo
{
struct strFields
{
CString foo::* pS;
int fldIdx;
};
CString mStr;
static const strFields lentab[];
};
const foo::strFields foo::lentab[] = {
{ &mStr, 1},
};
This compiles with MSVC, but g++ says 'illegal use of foo::mStr'. This error message gave me a really hard time, util I found
const foo::strFields foo::lentab[] = {
{ &foo::mStr, 1},
};
compiles perfectly.
- --------------------
Diff 2. - typename
With MSVC i never used this keyword, and everything compiled. Then g++ requires it everywhere. sometimes suggesting use of typename, other times just wit generic parse error.
having something like:
template<class TYPE> // return: ennyi rekordot olvasott fel
void foo( typename TYPE::tRset * pRset = 0) {}
could tRset be anything but a typename? Is it allowed and/or nice requiring it?
- ------------------
Diff 3. - static cast enums
Having
enum eG
{
eg_value,
};
struct foo
{
enum {myVal = eg_value};
eG GetMyval() { return static_cast<eG>(myVal);}
};
This compiles with MSVC, g++ rejects with 'cant static_cast from unnamed enum to enum eG. Using
static_cast<eG>( int(myVal));
instead cures the problem but I don't like it at all. Does the standard forbid static_casting between different enums? If so, why, and how I'm supposed to do it 'the nice way' ?
- ------------------
Diff 4. - forward declaring enum
This is not really a question, I know it is not allowed by the standard, and MS supports it as extension. I could really use it with g++, paying the price of my enums being as big az an int. (The only switch i found made enums ints completely, making them assignable with ints, etc, not fitting me.)
- -------------------
Diff 5 -- ?:
I had to fix the following line:
pf ? pf->GetFileName() : ""
to
pf ? LPCSTR(pf->GetFileName()) : ""
to make it compile.
things used are:
typedef const char * LPCSTR;
CFile * pf;
CString CFile::GetFileName( ) const;
and CString having a ctor CString( LPCSTR lpsz );
CString also has operator LPCSTR () const;
Unfortunately i can't recall the exact diagnostic of g++, but id did not contain 'ambiguous' or a like stuff for sure.
As I see it both expressions can be converted to the other's type. should it be considered ambiguous? Or there's a rule to select order? Is this really to be rejected, and MSVC compiles it through a bug or extension, or g++ is too picky?
- ---------------
Diff 5 -- inherited static
Having
struct fooBase
{
static const int iarr[3];
};
struct foo : fooBase
{
};
const int foo::iarr[3] = {1,2,3};
It was an actual bug in the code, but was unnoticed this far.
the correct version is certainly
const int fooBase::iarr[3] = {1,2,3};
MSVC compiles it without complaint. is that a bug or a feature?
- -----------
---
[ 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: Itai Danan <idanan@yahoo.com>
Date: Thu, 13 Dec 2001 18:49:02 CST Raw View
Balog Pal wrote:
>
> I'm porting a set of code from under MSVC to a g++/linux and experience interesting differences.
> I want to know if what I observe is a bug in either compiler or what. :)
>
> Diff 1. ptm
>
> struct foo
> {
> struct strFields
> {
> CString foo::* pS;
> int fldIdx;
> };
> CString mStr;
>
> static const strFields lentab[];
> };
>
> const foo::strFields foo::lentab[] = {
> { &mStr, 1},
> };
>
> This compiles with MSVC, but g++ says 'illegal use of foo::mStr'. This error message gave me a really hard time, util I found
>
> const foo::strFields foo::lentab[] = {
> { &foo::mStr, 1},
> };
>
> compiles perfectly.
That is one of the numerous bugs in g++.
> - --------------------
> Diff 2. - typename
>
> With MSVC i never used this keyword, and everything compiled. Then g++ requires it everywhere. sometimes suggesting use of typename, other times just wit generic parse error.
>
> having something like:
>
> template<class TYPE> // return: ennyi rekordot olvasott fel
> void foo( typename TYPE::tRset * pRset = 0) {}
>
> could tRset be anything but a typename? Is it allowed and/or nice requiring it?
The keyword typename is required here. THis is one the numerous bugs in
MSVC.
It is required whenever you have a name dependent on a template
parameter
that is a type. There are exceptions where it is not required: to
specify a base
class in a class declaration and as a member in an initializer list for
a constructor.
> - ------------------
> Diff 3. - static cast enums
>
> Having
>
> enum eG
> {
> eg_value,
> };
>
> struct foo
> {
> enum {myVal = eg_value};
>
> eG GetMyval() { return static_cast<eG>(myVal);}
> };
>
> This compiles with MSVC, g++ rejects with 'cant static_cast from unnamed enum to enum eG. Using
> static_cast<eG>( int(myVal));
>
> instead cures the problem but I don't like it at all. Does the standard forbid static_casting between different enums? If so, why, and how I'm supposed to do it 'the nice way' ?
Don't know about this one. I would guess g++ to be wrong here.
- Itai
---
[ 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: Nathan Sidwell <nathan@acm.org>
Date: Sat, 15 Dec 2001 08:51:49 CST Raw View
Balog Pal wrote:
>
> I'm porting a set of code from under MSVC to a g++/linux and experience interesting
differences.
> I want to know if what I observe is a bug in either compiler or what. :)
>
> Diff 1. ptm
> const foo::strFields foo::lentab[] = {
> { &mStr, 1},
> };
>
> This compiles with MSVC, but g++ says 'illegal use of foo::mStr'.
g++ is correct, a pointer to member is only formed by '&TYPE::member'.
see [5.3.1]/3
> const foo::strFields foo::lentab[] = {
> { &foo::mStr, 1},
> };
this is well formed.
> Diff 2. - typename
>
> With MSVC i never used this keyword, and everything compiled. Then g++ requires it
everywhere. sometimes suggesting use of typename, other times just wit
generic parse
error.
> template<class TYPE> // return: ennyi rekordot olvasott fel
> void foo( typename TYPE::tRset * pRset = 0) {}
>
> could tRset be anything but a typename? Is it allowed and/or nice requiring it?
typename is required. 'TYPE::tRset' is a dependant name (its meaning
depends on template parameter TYPE'). Such qualified names are assumed
not to name a type, unless preceeded by 'typename'. See [14.6]/2
> Diff 3. - static cast enums
> eG GetMyval() { return static_cast<eG>(myVal);}
> This compiles with MSVC, g++ rejects with 'cant static_cast from unnamed enum to
enum eG. Using
This is a defect in the standard. [5.2.9] does not allow such a
conversion. Defect report 128 talks about this. G++ 3.0 et seq
support the suggested resolution to that DR.
> Diff 4. - forward declaring enum
> Diff 5 -- ?:
> pf ? pf->GetFileName() : ""
> Unfortunately i can't recall the exact diagnostic of g++, but id did not contain
'ambiguous' or a like stuff for sure.
You've not provided enough information, but there are some wierdnesses
with the semantics of the ?: operator, plus "" is of type
'const char [1]', not 'const char *'
> Diff 5 -- inherited static
>
> Having
>
> struct fooBase
> {
> static const int iarr[3];
> };
> struct foo : fooBase
> {
> };
> const int foo::iarr[3] = {1,2,3};
> MSVC compiles it without complaint. is that a bug or a feature?
it is a deviation from the standard. If it is documented it is a
feature, otherwise it's a bug (aka undocumented feature :-)
nathan
--
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
The voices in my head told me to say this
nathan@acm.org http://www.cs.bris.ac.uk/~nathan/ nathan@cs.bris.ac.uk
---
[ 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: jthill_@mac.com (Jim Hill)
Date: 16 Dec 2001 06:49:38 -0500 Raw View
The standard costs USD18.00 at http://webstore.ansi.org (specifically,
<http://webstore.ansi.org/ansidocstore/product.asp?sku=ISO%2FIEC+14882%2D1998>).
You could have it in less than half an hour at 28.8Kbps.
"Balog Pal" <pasa@lib.hu> wrote in message news:<3c1922cf@andromeda.datanet.hu>...
> struct foo {
> struct strFields {
> CString foo::* pS;
> int fldIdx;
> };
> CString mStr;
> static const strFields lentab[];
> };
> const foo::strFields foo::lentab[] = { { &mStr, 1}, };
3.4.1 "Unqualified name lookup", under 3.4 "Name lookup", under 3
"Basic Concepts". 3.4.1 paragraph 12 (they're numbered) starts "A name
used in the definition of a static data member of class X", which this
is, "is looked up as if the name was used in a member function of X."
Well, thanks guys. Rereading the section from the top gets us to p8,
which starts "A name used in the definition of a function that is a
member function of class X".
The first place that paragraph says to look is the usual place: the
current (global, here) scope up to where the name is used. There's no
mStr there. The next place is "a member of class X or be a member of
a base class of X".
mStr is member, and so g++ should have found it. It's a g++ bug.
> - --------------------
> template<class TYPE> // return: ennyi rekordot olvasott fel
> void foo( typename TYPE::tRset * pRset = 0) {}
>
> Is it allowed and/or nice requiring [typename]?
Here's another name lookup rule, this time for a qualified id.
Searching 3.4.3, "qualified name lookup" yields nothing. Well, thanks
guys. Now what?
It's a template. Try "Templates", chapter (the pedantic term is
"clause") 14? Ah: 14.6 is "Name Resolution", and 14.6p3 says "A
qualified name that refers to a type and that depends on a template
parameter (14.6.2) shall be prefixed by the keyword typename to
indicate that the qualified name denotes a type, forming an
elaborated type specifier (7.1.5.3)." So you have to use the keyword.
I think there should be a note in 3.4 pointing to the additional rules
for templates in 14.6 (or is there, and I missed it?).
> - ------------------
> enum eG { eg_value, };
>
> struct foo {
> enum {myVal = eg_value};
> eG GetMyval() { return static_cast<eG>(myVal);}
> };
>
> g++ rejects with 'cant static_cast from unnamed enum to enum eG. Using
Checking the rules for `static_cast<T>(e)` says a whole lot of things,
the relevant one of which is that you can do it if the declaration `T
t(e)` would be valid (for some invented variable t). Hunting down
initializers means stumbling over the distinction between
'declarations' and 'declarators', which is annoying and irrelevant if
you don't want to learn how to talk about details of the language but
do want to know exactly what you can do with it.
Anyway, looking at the table of contents turns up 8.5 'initializers'
under clause 8 'Declarators', and there's a long list of specific
cases that clearly don't apply here, and then 8p14, which starts "the
semantics of initializers are as follows", _another_ long list of
specific cases that clearly don't apply, and then "Otherwise, the
initial value of the object being initialized is the (possibly
converted) value of the initializer expression. Standard conversions
(clause 4) will be used, if necessary, to convert the initializer
expression to the cv-unqualified version of the destination type; no
user-defined conversions are considered. If the conversion cannot be
done, the initialization is ill-formed."
So if it's valid, there's a standard conversion to do it. Reading
through clause 4, there isn't one. You can get from enum to int via
standard conversion, but not from enum to enum. So you'll have to
spell it out.
> static_cast<eG>( int(myVal));
>
> instead cures the problem but I don't like it at all. [H]ow am I
> supposed to do it 'the nice way' ?
I think it's not nice to treat unrelated types this way, and different
enum types are unrelated. If you want different rules, use another
type. That's what classes are for. It's easy enough to do:
template<typename stored, typename converted> class eitherenum {
stored value;
public:
eitherenum() : value(stored(0)) {}
eitherenum(eitherenum v) : value(v) {}
eitherenum(converted v) : value(stored(int(v))) {}
eitherenum(stored v) : value(stored(int(v))) {}
operator converted() { return converted(int(value)); }
operator stored() { return value; }
operator int() { return value; }
};
enum A { amax=90 };
enum B { bmax=900000 };
int main() {
eitherenum<A,B> ab(amax), ab1, ab2(bmax); A a(amax); B b(bmax);
ab=a; ab=b; a=ab; b=ab2; ab1=ab;
}
> - ------------------
> Diff 4. - forward declaring enum
>
> I could really use it, paying the price of my enums being as big as
> an int.
I think that would be good too, but it would mean _all_ enums must be
as big as an int. On balance: nope. This is currently the only
portable way to declare "just big enough for these values", and doing
that means a specific type of values, for which the restrictions are
almost certainly meaningful anyway.
> - -------------------
>
> pf ? pf->GetFileName() : ""
[ ^ returns CString, convertible to and from const char * ]
> As I see it both expressions can be converted to the other's type.
> should it be considered ambiguous? Or there's a rule to select order?
Back to straight reading. 5.16p3: if each of the second and third
operands can be implicitly converted to the other, the type of the
expression as a whole is ambiguous and the program is ill-formed.
> - -------------------
> struct fooBase { static const int iarr[3]; };
> struct foo : fooBase { };
>
> const int foo::iarr[3] = {1,2,3};
This one is a two-stepper: 3.4.3.1p1, qualified name lookup for class
members. `iarr` here is looked up (as if unqualified) in the scope of
class foo. So there's no question which 'iarr' this is referring to.
But this is a definition as well as a use, and there are specific
rules for them. This usage violates a constraint in 8.3p1, i.e. the
first paragraph discussing the meaning of declarators: the name must
have been previously declared as a member of the class (or namespace)
named before the '::'. iarr can be found via foo, but it wasn't
declared there.
So it's wrong.
===
This took about an hour of my time. You're asking questions that can
be answered by reading the manual we're discussing here. Please: buy
it and learn to read it.
Jim
---
[ 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: jthill_@mac.com (Jim Hill)
Date: 16 Dec 2001 13:54:02 -0500 Raw View
jthill_@mac.com (Jim Hill) wrote in message news:<a8af2f56.0112141333.5fb82884@posting.google.com>...
> Please: buy it and learn to read it.
Gaaah. Of course if I'm going to say that I should be more careful
about when I stop reading it myself. The name mStr in the first
question is accessible, but there's a constraint on forming
pointers-to-member: the member name must be qualified and must
immediately have its address taken. The example violates that
constraint, and I didn't bother checking past the name lookup. My
apologies.
Jim
---
[ 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 ]