Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Strange bug: struct is not a type in C++?

Reply
Thread Tools

Strange bug: struct is not a type in C++?

 
 
jdmuys
Guest
Posts: n/a
 
      10-08-2008
Hi,

I have a strange bug in my code, which I managed to reduce to the tiny
C++ program below.

The compiler reject the "class1<Type>::insideStruct *p2;" declaration
with the following error message:

/.../main.cpp:23: error: expected ';' before '*' token

while prepending "struct" in front of the declaration makes it quite
happy.

Since in C++, structs are types, this shouldn't be: either they are
both correct or they are both incorrect.

Did I miss something? Is this a compiler bug (I tried two different
compilers including GCC4 on MacOS X)? or my bug?

Thanks for the help,

Jean-Denis.

#include <iostream>

template<class Type>
class class1
{

public:
struct insideStruct
{
int anyInt;
Type fData;
};

insideStruct class1Data;
};

template<class Type>
class class2
{
public:
int class2int;
struct class1<Type>::insideStruct *p1; // Compiler is just fine with
this
class1<Type>::insideStruct *p2; // but doesn't like this
};


int main (int argc, char * const argv[]) {
std::cout << "Hello, Lucky World!\n";
class1<double> c1;
class2<double> c2;
std::cout << "class1 size: " << sizeof(c1) << "\n";
std::cout << "class2 size: " << sizeof(c2) << "\n";
return 0;
}
 
Reply With Quote
 
 
 
 
Marcel Müller
Guest
Posts: n/a
 
      10-08-2008
Hi,

jdmuys schrieb:
> template<class Type>
> class class2
> {
> public:
> int class2int;
> struct class1<Type>::insideStruct *p1; // Compiler is just fine with
> this
> class1<Type>::insideStruct *p2; // but doesn't like this


typename class<Type>::insideStruct *p2;

> };


Implicit typenames in templates are deprecated for a while.


Marcel
 
Reply With Quote
 
 
 
 
Leandro Melo
Guest
Posts: n/a
 
      10-08-2008
On 8 out, 08:24, jdmuys <(E-Mail Removed)> wrote:
> Hi,
>
> I have a strange bug in my code, which I managed to reduce to the tiny
> C++ program below.
>
> The compiler reject the "class1<Type>::insideStruct *p2;" declaration
> with the following error message:
>
> /.../main.cpp:23: error: expected ';' before '*' token
>
> while prepending "struct" in front of the declaration makes it quite
> happy.
>
> Since in C++, structs are types, this shouldn't be: either they are
> both correct or they are both incorrect.
>
> Did I miss something? Is this a compiler bug (I tried two different
> compilers including GCC4 on MacOS X)? or my bug?
>
> Thanks for the help,
>
> Jean-Denis.
>
> #include <iostream>
>
> template<class Type>
> class class1
> {
>
> public:
> * * * * struct insideStruct
> * * * * {
> * * * * * * * * int anyInt;
> * * * * * * * * Type fData;
> * * * * };
>
> * * * * insideStruct class1Data;
>
> };
>
> template<class Type>
> class class2
> {
> public:
> * * * * int class2int;
> * * * * struct class1<Type>::insideStruct *p1; // Compiler is just fine with
> this
> * * * * class1<Type>::insideStruct *p2; // but doesn't like this
>
> };
>
> int main (int argc, char * const argv[]) {
> * *std::cout << "Hello, Lucky World!\n";
> * * * * class1<double> c1;
> * * * * class2<double> c2;
> * * * * std::cout << "class1 size: " << sizeof(c1) << "\n";
> * * * * std::cout << "class2 size: " << sizeof(c2) << "\n";
> * *return 0;
>
> }


Try this:

typename class1<Type>::insideStruct *p2;


--
Leandro T. C. Melo


 
Reply With Quote
 
jdmuys
Guest
Posts: n/a
 
      10-09-2008
On Oct 8, 1:45*pm, Leandro Melo <(E-Mail Removed)> wrote:

> typename class1<Type>::insideStruct *p2;
>


Yep, that's it: the line must be prepended by the "typename" keyword.

The reason is that there is no unambiguous way to tell what the
"class1<Type>::X *p2" is until class1 is instanciated. It can be two
very different things:

1- A pointer declaration, when X is a type inside class1. This is the
original intent.
2- a multiplication (!!), when X is (for example), an int member of
class1. This could happen.

This is why the C++ standard now says that an identifier that is both
qualified (using the :: scope resolution operator) AND dependent
(parameterized) is NOT automatically a type.

Prepending it with "typename" makes it a type:

typename class1<Type>::insideStruct *p2;

This also explains why prepending struct works as well. With struct,
the line says that X is a struct, and since a struct is automatically
a type in C++, the compiler is happy.

However the "struct" workaround is less general and not idiomatic.

I had not written any significant C++ code since 2003. Since then the C
++ standard has evolved!

Thanks and best regards to all.

Jean-Denis
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      10-09-2008
jdmuys wrote:
> The reason is that there is no unambiguous way to tell what the
> "class1<Type>::X *p2" is until class1 is instanciated. It can be two
> very different things:
>
> 1- A pointer declaration, when X is a type inside class1. This is the
> original intent.
> 2- a multiplication (!!), when X is (for example), an int member of
> class1. This could happen.


When you want to specify option 1, you use the keyword 'typename'.
However, how can you specify that you really want it to be interpreted
as option 2?

(Or is it so that it's by default interpreted as option 2, which
causes the error because the parameters are not valid for the binary
operator*, and you have to specify the 'typename' if you want to tell
the compiler that this is a type declaration, not a call to operator*?)
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      10-10-2008
On Oct 9, 1:26 pm, Juha Nieminen <(E-Mail Removed)> wrote:
> jdmuys wrote:
> > The reason is that there is no unambiguous way to tell what
> > the "class1<Type>::X *p2" is until class1 is instanciated.
> > It can be two very different things:


> > 1- A pointer declaration, when X is a type inside class1.
> > This is the original intent.
> > 2- a multiplication (!!), when X is (for example), an int
> > member of class1. This could happen.


> When you want to specify option 1, you use the keyword
> 'typename'. However, how can you specify that you really want
> it to be interpreted as option 2?


> (Or is it so that it's by default interpreted as option 2,
> which causes the error because the parameters are not valid
> for the binary operator*, and you have to specify the
> 'typename' if you want to tell the compiler that this is a
> type declaration, not a call to operator*?)


The goal is that the compiler can reasonably parse a template
before any instantiation. To do this, practically, for each
symbol, it must know whether the symbol is bound to a type, a
template or something else. For dependent symbols (those whose
actual binding depends on the instantiation), the compiler
assumes something else, unless you tell it differently (typename
or template keywords). If, during actual instantiation, it
turns out that the assumption was wrong (you lied, or you forgot
to tell it), the program is ill-formed, and you get an error
message.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
jdmuys
Guest
Posts: n/a
 
      10-10-2008
On Oct 9, 1:26*pm, Juha Nieminen <(E-Mail Removed)> wrote:
> jdmuys wrote:
> > The reason is that there is no unambiguous way to tell what the
> > "class1<Type>::X *p2" is until class1 is instanciated. It can be two
> > very different things:

>
> > 1- A pointer declaration, when X is a type inside class1. This is the
> > original intent.
> > 2- a multiplication (!!), when X is (for example), an int member of
> > class1. This could happen.

>
> * When you want to specify option 1, you use the keyword 'typename'.
> However, how can you specify that you really want it to be interpreted
> as option 2?
>
> * (Or is it so that it's by default interpreted as option 2, which
> causes the error because the parameters are not valid for the binary
> operator*, and you have to specify the 'typename' if you want to tell
> the compiler that this is a type declaration, not a call to operator*?)


In essence yes: the compiler (GCC4 at least) defaults to
multiplication, as the example below shows. Look in class2method():

std::cout << class1<Type>::value *p4 << "\n"; // multiplication case
std::cout << class1<Type>::insideStruct *p3; // there is no way to
use the typename case with cout

the first line above compiles fine and prints 15 as expected.
the second line above doesn't compile with the following error
message:

/.../main.cpp:38: error: dependent-name 'class1<Type>::insideStruct'
is parsed as a non-type, but instantiation yields a type

It says the line is parsed as "non-type": the defaults is thus
multiplication.

The full program code follows: simply comment out that failing line,
and all runs fine then.

Jean-Denis


#include <iostream>

template<class Type>
class class1
{

public:
struct insideStruct
{
int anyInt;
Type fData;
};

insideStruct class1Data;
const static int value = 3;
};

template<class Type>
class class2
{
public:
int class2int;
struct class1<Type>::insideStruct *p1; // Compiler is just fine with
this
typename class1<Type>::insideStruct *p2; // and now also with this

void class2method()
{
std::cout << "trying both use case inside a parameterized class
member function\n";
std::cout << p1 << "\n";
std::cout << p2 << "\n";

typename class1<Type>::insideStruct *p3; // type case
std::cout << p3 << "\n";
int p4 = 5;
class1<Type>::value *p4; // multiplication case
std::cout << class1<Type>::value *p4 << "\n"; // the same used with
cout
// note: there is no way to use the typename case with cout, such
as:
std::cout << class1<Type>::insideStruct *p3; // type case

}
};


int main (int argc, char * const argv[]) {
// insert code here...
std::cout << "Hello, Lucky World!\n";
class1<long> c1;
class2<double> c2;
std::cout << "class1 size: " << sizeof(c1) << "\n";
std::cout << "class2 size: " << sizeof(c2) << "\n";
c2.class2method();
return 0;
}
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
static struct initialization in a Class:: -- not my struct christian.bongiorno@gmail.com C++ 2 09-20-2006 06:53 PM
cannot dynamic_cast 't' (of type 'void*') to type 'struct mom::object*' (source is not a pointer to class) verec C++ 5 08-15-2005 11:02 PM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM
To coerce or not...? struct sockaddr vs struct sockaddr_in James Harris C Programming 4 10-09-2003 10:06 PM



Advertisments