9
votes

I have the following code (simplified), which compiles fine in gcc, but gives an error in VS:

// main.cpp
#include "test.h"
int main() {
  return 0;
}

// test.h
#pragma once
class Test {
  static const int TEST = 3;
};

// test.cpp
#include "test.h"
const int Test::TEST;

Error:

main.obj : error LNK2005: "private: static int const Test::TEST" (?TEST@Test@@0HB) already defined in test.obj

Is it a VS bug or is gcc incorrectly allowing me to define the static const member explicitly?

Update: found this in the C++ Standard (9.4.2.3):

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

Update #2: found a bug report, which claims that it is fixed in the next major version.

2
What if you remove const int Test::TEST; from your test.cpp, will gcc compile the code?ixSci
It seems to work, but I'm working with code that explicitly defines those lines and don't want to edit it as it will break again on the next svn update.riv
Thanks, I just wanted to know if gcc has a bug of a different kind. I thought it requires you to define the constant explicitly in all cases. But if it doesn't then there is a bug in MSVC only.ixSci
On a side note, I'd use an enum here, which would conveniently avoid this bug as well.EboMike

2 Answers

4
votes

Exactly as you said it was a MSVC bug. The code compiles and runs perfectly in Visual Studio 2015 RC with default project options.

enter image description here

The compiler thinks "static const int TEST = 3;" and "const int Test::TEST;" are two different definitions of the same variable. To fix this in your version you could try setting the static variable value in the .cpp file:

// test.h
#pragma once
class Test {
  static const int TEST;
};

// test.cpp
#include "test.h"
const int Test::TEST = 3;
1
votes

With Microsoft Extensions to C and C++ enabled, compiler generates the out-of-class definition automatically. Some compiler versions are probably buggy and do this auto-definition even when you defined it manually (e.g. when writing portable code).

You can either disable the extensions, or check for _MSC_EXTENSIONS macro. It's defined when the /Ze option is set. For example:

#ifndef _MSC_EXTENSIONS
   const int MyClass::MyStaticMember;
#endif