Is this a bug of the C++ compiler of VS 2005?

L

Lighter

See an example at first:

hdr.h
--------------

struct X
{
static const int m = 9;
};

=====================

source1.cpp
---------------

#include "hdr.h"

const int X::m;

=====================

main.cpp
---------------

#include "hdr.h"

int main()
{}

=====================

link error:
source1.obj : error LNK2005: "public: static int const X::m" (?
m@X@@2HB) already defined in main.obj


According to the C++ standard 9.4.2/4
"If a static data member is of const integral or const enumeration
type, its
declaration in the class definition can specify a constant-initializer
which
shall be an integral constant expression. In that case, the member
can
appear in integral constant expressions within its scope. The member
shall
still be defined in a namespace scope if it is used in the program and
the
namespace scope definition shall not contain an initializer."

Judging from the rule above, my code is correct. However, if I
commented the statement: const int X::m; then everything is ok. Why?
 
V

Victor Bazarov

Lighter said:
See an example at first:

hdr.h
--------------

struct X
{
static const int m = 9;
};

=====================

source1.cpp
---------------

#include "hdr.h"

const int X::m;

=====================

main.cpp
---------------

#include "hdr.h"

int main()
{}

=====================

link error:
source1.obj : error LNK2005: "public: static int const X::m" (?
m@X@@2HB) already defined in main.obj


According to the C++ standard 9.4.2/4
"If a static data member is of const integral or const enumeration
type, its
declaration in the class definition can specify a constant-initializer
which
shall be an integral constant expression. In that case, the member
can
appear in integral constant expressions within its scope. The member
shall
still be defined in a namespace scope if it is used in the program and
the
namespace scope definition shall not contain an initializer."

Judging from the rule above, my code is correct. However, if I
commented the statement: const int X::m; then everything is ok. Why?

Looks like a defect in their linker. Post to the VC++ newsgroup and/or
submit a bug report to Microsoft.

V
 
W

witkamp

This is standard C++ behavior.

Just remove the "= 9" from your struct definition and it will work the
way you would expect.
 
Z

Zeppe

witkamp said:
This is standard C++ behavior.

Just remove the "= 9" from your struct definition and it will work the
way you would expect.

lol. Of course, removing a piece the program solves the problem :)

But have you read the message? Why should him remove =9 if he wants his
const static int member to be initialized in the class definition?
He also cited the standard, so, if you do not agree with something,
please provide an explanation.

Regards,

Zeppe
 
G

Gennaro Prota

Looks like a defect in their linker. Post to the VC++ newsgroup and/or
submit a bug report to Microsoft.

I don't know if it has ever been reported but it is an old bug, dating
back at least to VC 7.1. It is affected by the /Za flag, BTW: usually
/Za will make everything link, but then the resulting exe might not
work at all (great, isn't it? 98% conformity). This happens for
instance in the unit tests for


<http://breeze.svn.sourceforge.net/viewvc/breeze/trunk/breeze/meta/maximum.hpp>

but also in much simpler cases.
 
S

Sascha Bohnenkamp

Visual C++ is not an iso-compliant compiler ...
(no matter which version)
 
Z

Zeppe

Sascha said:
Visual C++ is not an iso-compliant compiler ...
(no matter which version)

None of the current compilers is an iso-compliant compiler. Visual C++
is a good compiler, if you have some specific issue we can discuss them,
like in the OP post, but please, refrain from trolling.

Regards,

Zeppe
 
K

Krice

However, if I
commented the statement: const int X::m; then everything is ok. Why?

Because m is defined in the struct already. You don't need
another definition.
 
Z

Zeppe

Krice said:
Because m is defined in the struct already. You don't need
another definition.

c'mon guys. Let's read the messages before answering ;)

Regards,

Zeppe
 
B

Bo Persson

Krice wrote:
:: However, if I
:: commented the statement: const int X::m; then everything is ok.
:: Why?
:
: Because m is defined in the struct already. You don't need
: another definition.

You do actually, but sometimes you get away with it.

Try passing the value by const reference, like to std::max(), and the
linker will now complain that it cannot find the definition.


Bo Persson
 
G

Gavin Deane

Because m is defined in the struct already.

No it's not. It's declared and given an initialiser.
You don't need
another definition.

The OP's code doesn't have "another" definition, it has exactly one
definition.

Reread the section of the standard that the OP quoted.

Gavin Deane
 
W

Wanderley Caloni

This is standard C++ behavior.

No, it is not. As quoted by the colleague, the Standard allows the
initialization inside the class declaration, but one still needs to
define the variable outside. What the Visual Studio does is to allow
the declaration without definition, defining it automatically. When
one defines the same variable, the VS "help" ends messing up the code.

You're right, Lighter, the VS behavior is error prone regard to the
Standard Spec.

Wanderley Caloni
======================
http://www.cthings.org
 
P

ppl

See an example at first:

hdr.h
--------------

struct X
{
staticconstint m = 9;

};

=====================

source1.cpp
---------------

#include "hdr.h"

constint X::m;

=====================

main.cpp
---------------

#include "hdr.h"

int main()
{}

=====================

linkerror:
source1.obj : error LNK2005: "public:staticintconstX::m" (?
m@X@@2HB) already defined in main.obj

According to the C++ standard 9.4.2/4
"If astaticdata member is ofconstintegralorconstenumeration
type, its
declaration in the class definition can specify a constant-initializer
which
shall be anintegralconstant expression. In that case, the member
can
appear inintegralconstant expressions within its scope. The member
shall
still be defined in a namespace scope if it is used in the program and
the
namespace scope definition shall not contain an initializer."

Judging from the rule above, my code is correct. However, if I
commented the statement:constint X::m; then everything is ok. Why?

I did observe the same problem in VC++2003 recently. I've read the
same paragraph of the standard and came to the same conclusion.

This problem can become tricky when you are also dealing with g++. The
GNU compiler properly implement the standard (afaik) and will yield a
linking error if you do not properly define m in a translation unit.
However, if you omit m definition, it may not yield a linking error in
some cases where, I assume, m references are inlined.

An example of this is when you use m directly (e.g. X::m) it may be
inlined and may not yield a linking error. Otoh, if you access m
indirectly via a non-inline method, g++ will generate the linking
error if you omit m definition.

See also http://docs.freebsd.org/info/g++FAQ/g++FAQ.info.static_data_members.html

We resolved to simply remove the initializer in the declaration and
place it in the definition. This will work with g++ and fix the issue
with VC++2003/2005.

Please inform me if someone already wrote a bug report to Microsoft
and/or know of an acknowledgment of this problem on Microsoft website.

Thank you,
ppl
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top