compilation error with enum.

S

subramanian

Hello.
Consider the following code fragment :

enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

class Test {
public :
enum TestEnum { val1 = 1, val2 val3 };
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));
...
private :
int x, y;
TestEnum a;
static Test default_test;
};

Test Test::default_test(1, 2, val1);

int main(void)
{
Test temp_test(1, 2, val1);
...
}
--------------------------------------------------------------

QUESTIONS:

1)
I am getting compilation error for Test temp_test(1, 2, val1); val1 is
not taken from global enum TestEnum nor the Test::val1. However in the
static member definition,
Test Test::default_test(1, 2, val1);
val1 is considered to be Test::val1. Here I am not getting compilation
error. Why is this difference, considering that both are ctors where
val1 appears.

2)
In the static class member definition
Test Test::default_test(1, 2, val1);
val1 is taken from Test::val1. Why is not the global val1 considered ?
 
S

Sean Fritz

subramanian said:
Hello.
Consider the following code fragment :

enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

class Test {
public :
enum TestEnum { val1 = 1, val2 val3 };
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));
...
private :
int x, y;
TestEnum a;
static Test default_test;
};

Test Test::default_test(1, 2, val1);

int main(void)
{
Test temp_test(1, 2, val1);
...
}
--------------------------------------------------------------

QUESTIONS:

1)
I am getting compilation error for Test temp_test(1, 2, val1); val1 is
not taken from global enum TestEnum nor the Test::val1. However in the
static member definition,
Test Test::default_test(1, 2, val1);
val1 is considered to be Test::val1. Here I am not getting compilation
error. Why is this difference, considering that both are ctors where
val1 appears.
Might need more information to answer this correctly (declared functions of
Test as well as their defined form). Your code is a bit confusing, and I
think posting the whole thing might help.
2)
In the static class member definition
Test Test::default_test(1, 2, val1);
val1 is taken from Test::val1. Why is not the global val1 considered ?
Test::val1 has global scope, but the other val1 (which has file scope)
overrides it. You can explicitly call the val1 you want using Test::val1,
but it's generally a better practice to make Test::val1 private and use a
public getter function to retrieve and and a public setter function to
change it.
 
S

subramanian

Consider the complete code:

#include <iostream>

enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

class Test {
public :
enum TestEnum { val1 = 1, val2, val3 };
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));

private :
int x, y;
TestEnum a;
static Test default_test;
};

Test Test::default_test(1, 2, val1);

Test::Test(int i, int j, TestEnum val)
{
x = i;
y = j;
a = val;

std::cout << "x = " << x << " y = " << y << " a = " << a << '\n';
return;
}

int main(void)
{
// Test temp_test(1, 2, val1);

return 0;
}

This progam compiles without errors. When I run this program, the
following output is generated:

x = 1 y = 2 a = 1

This output corresponds to the statement
Test Test::default_test(1, 2, val1);

Here val1 is taken from Test::val1 as can be seen from the output value
1 (not 10). I thought val1 should be the global enum val1 = 10. What is
the expected behaviour ?

Now consider the following commented statement present in main:
// Test temp_test(1, 2, val1);

If I remove the comment, I am getting the following compilation error
for the third argument val1. (This is in VC++ 2005 Express edition.)

'Test::Test(int,int,Test::TestEnum)' : cannot convert parameter 3 from
'TestEnum' to 'Test::TestEnum'

Does it mean that the third parameter val1 is considered from the
global TestEnum not the Test class' TestEnum ?. But in the previous
definition of the static Test::default_test, Test::val1 is used even
though the same ctor is used. What is the difference between these two
ctor calls ?

(Note: With g++ also, I am getting the same output
x = 1 y = 2 a = 1

and a compilation error for the commented statement when the comment is
removed)

Kindly clarify
 
J

Jim Langston

subramanian said:
Consider the complete code:

#include <iostream>

enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

class Test {
public :
enum TestEnum { val1 = 1, val2, val3 };
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));

private :
int x, y;
TestEnum a;
static Test default_test;
};

Test Test::default_test(1, 2, val1);

Test::Test(int i, int j, TestEnum val)
{
x = i;
y = j;
a = val;

std::cout << "x = " << x << " y = " << y << " a = " << a << '\n';
return;
}

int main(void)
{
// Test temp_test(1, 2, val1);

return 0;
}

This progam compiles without errors. When I run this program, the
following output is generated:

x = 1 y = 2 a = 1

This output corresponds to the statement
Test Test::default_test(1, 2, val1);

Here val1 is taken from Test::val1 as can be seen from the output value
1 (not 10). I thought val1 should be the global enum val1 = 10. What is
the expected behaviour ?

Now consider the following commented statement present in main:
// Test temp_test(1, 2, val1);

If I remove the comment, I am getting the following compilation error
for the third argument val1. (This is in VC++ 2005 Express edition.)

'Test::Test(int,int,Test::TestEnum)' : cannot convert parameter 3 from
'TestEnum' to 'Test::TestEnum'

And that tells you exactly what the problem is. The class defintion of
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));
is getting it's definition of TextEnum from the enum in the class.

In main, however, it sees val1 as coming from the global TestEnum.

"from TestEnum to Test::TestEnum"
could be rephrases as:
"from ::TestEnum to Test::TestEnum"
with ::TestEnum being in the unnamed namespace.

One way in man is to make it:
Test temp_test( 1, 2, Test::TestEnum::val1 );

The other way is to get rid of the enum definition inside of your class so
it also uses the one n the unnamed namespace.
 
S

Sean Fritz

subramanian said:
enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

I'm not quite sure why you are trying to name an enum.
class Test {
public :
enum TestEnum { val1 = 1, val2, val3 };

Same comment as above.
Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));

I see that you are defining the ctor outside the class, we don't use any
names here. TestEnum isn't a type.
Test( int, int, int );
int x, y;
TestEnum a;

Again, TestEnum not a type.
int x, y, a;
static Test default_test;

This should be taken out.
};

Test Test::default_test(1, 2, val1);

Need to define ctor:

Test::Test( int i, int j, int val )
:x( i ) //set Test::x to i
:y( j )
:a( val )
{
cout << "x = " << x << ", y = " << y << ", a = " << a << endl;
}

Test default_test( 1, 2, val1 ); // this part goes in main()
Test::Test(int i, int j, TestEnum val) // TestEnum is the name of an
{
x = i;
y = j;
a = val;

std::cout << "x = " << x << " y = " << y << " a = " << a << '\n';
return;
}

Remove this.

Maybe those changes will work?
 
S

Sean Fritz

Sean said:
I'm not quite sure why you are trying to name an enum.


Same comment as above.


I see that you are defining the ctor outside the class, we don't use any
names here. TestEnum isn't a type.
Test( int, int, int );


Again, TestEnum not a type.
int x, y, a;


This should be taken out.


Need to define ctor:

Test::Test( int i, int j, int val )
:x( i ) //set Test::x to i
:y( j )
:a( val )
{
cout << "x = " << x << ", y = " << y << ", a = " << a << endl;
}

Test default_test( 1, 2, val1 ); // this part goes in main()


Remove this.

Maybe those changes will work?

I'm still learning too, so I may be wrong sometimes.
 
S

subramanian

I first say that I am learning C++. As part of the learning exercise I
tried the above code.

Part of my doubt still persists.
I state it here.

In the statement

Test Test::default_test(1, 2, val1);

val1 is taken from Test::val1. However in the statement

Test temp_test(1, 2, val1);

val1 is taken from the global TestEnum. In both cases, same ctor is
called. So, I do not understand as to why in these two constructions,
val1 of different TestEnum is included.

Kindly clarify
 
A

Alf P. Steinbach

* Sean Fritz:
I'm not quite sure why you are trying to name an enum.

The name is used to refer to the enum type later on.

Same comment as above.


I see that you are defining the ctor outside the class, we don't use any
names here. TestEnum isn't a type.

TestEnum is a type.

Hth.,

- Alf
 
A

Alf P. Steinbach

* subramanian:
Hello.
Consider the following code fragment :

enum TestEnum { val1 = 10, val2 = 100, val3 = 1000 };

class Test {
public :
enum TestEnum { val1 = 1, val2 val3 };

Missing comma in the value list (always paste actual code).

Test(int i = 0, int j = 0, TestEnum val = TestEnum(0));
...
private :
int x, y;
TestEnum a;
static Test default_test;
};

Test Test::default_test(1, 2, val1);

This is a member definition. Identifiers are first looked up in the
scope of the class where the member (here default_test) is declared.
Thus 'val1' refers to Test::val1.

The actual rules are unfortunately very complex.

Instead of saying what I wrote above (a simplicifation that is
necessarily not 100% correct in all cases) §3.4/12 tells you that an
unqualified name used in the definition of a static data member of class
T is looked up in the same way as for the definition of a T member
function, and §3.4/8 then lists the possible places where such a name is
looked up, namely (1) a declaration before its use in the block in which
it is used or in an enclosing block (if the usage is in a block), (2) as
a member of T, which is the case here, (3) ..., more stuff about nested
classes and namespaces, yes, the details are complicated. ;-)

For example, don't ask me about the lookup of a member function's result
type -- is it "in" the definition wrt. name lookup, or not?

I'd have investigate that, but generally, I just qualify names to render
such questions moot. Which is generally a good idea anyway: explicit
code, not code relying on implicit things. For we all use a subset of
C++ that we're comfortable with, and must look up things outside that
sub-language, and implicit things make this very much harder....

int main(void)
{
Test temp_test(1, 2, val1);

This is not a member definition. Identifiers are therefore looked up in
the scope of the declaration, not in the scope of the class of the thing
being declared. The only unqualified 'val1' available here is the
global '::val1'. Which is not implicitly convertible to Test::TestEnum.
Which is generally a good thing, so that you know you're using the
wrong enum type -- simply write Test::val1 to use the correct 'val1'.
...
}
--------------------------------------------------------------

QUESTIONS:

1)
I am getting compilation error for Test temp_test(1, 2, val1); val1 is
not taken from global enum TestEnum nor the Test::val1. However in the
static member definition,
Test Test::default_test(1, 2, val1);
val1 is considered to be Test::val1. Here I am not getting compilation
error. Why is this difference, considering that both are ctors where
val1 appears.

See above.

2)
In the static class member definition
Test Test::default_test(1, 2, val1);
val1 is taken from Test::val1. Why is not the global val1 considered ?

See above.

Hth.,

- Alf
 
B

BobR

subramanian wrote in message ...
I first say that I am learning C++. As part of the learning exercise I
tried the above code.

What 'above code'? As Shultz said said:
Part of my doubt still persists. I state it here.
In the statement

Test Test::default_test(1, 2, val1);

Looks first for 'val1' *inside* the class scope, then outside the class
(global) if not found.
If you want the 'outside' enum:

Test Test::default_test( 1, 2, ::val1 );
// or: Test Test::default_test( 1, 2, TestEnum::val1 );
val1 is taken from Test::val1. However in the statement

Test temp_test(1, 2, val1);

Assume this is inside main(). So, the compiler first looks inside main()
scope for 'val1'. It does not find it so goes looking for it at global scope.
The compiler does not know to look in your class unless you tell it to:
'Test::val1'.
val1 is taken from the global TestEnum. In both cases, same ctor is
called. So, I do not understand as to why in these two constructions,
val1 of different TestEnum is included.
Kindly clarify

You seem to not understand 'scope'.
I still had this example/test laying around, try it.

#include <iostream> // #include <ostream>

int xyz(12345); // note global scope

int main(){
std::cout<<" ------- "<<std::endl;
int abc(0), bla(0), blabla(5); // normal: s/b one var per code line.
int xyz(5); // local scope (main)
{ // scope 1
int xyz(22); // local scope (un-named inside main)
std::cout<<"xyz="<<xyz<<std::endl;
} // scope 1 end
{ // scope 2
double xyz(3.14); // local scope (un-named inside main)
std::cout<<"xyz="<<xyz<<std::endl;
} // scope 2 end
std::cout<<"abc="<<abc<<" bla="<<bla
<<" xyz="<<xyz<<std::endl;
for( int bla(0); bla < blabla; ++bla){ // for has scope too.
++abc;
std::cout << " abc=" << abc << " bla=" << bla;
static int xyz(25); // local scope ( inside for() )
std::cout <<" xyz="<<xyz++<<" ::xyz="
<<( ::xyz++ )<<std::endl; // note global access
} // for(bla)
std::cout<<"abc="<<abc<<" bla="<<bla
<<" xyz="<<xyz<<std::endl;
std::cout<<" ------- "<<std::endl;
return 0;
} // main()

Compile and run that, note the output (esp. the different 'xyz's).
There are five different 'xyz' in that. Without the scoping you would break
the one-definition rule (ODR).

[ Just because you can, should you? Using the same name for different things
can lead to confusion. ]
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top