Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VS2013 - static const already defined

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.

like image 633
riv Avatar asked Jun 26 '15 13:06

riv


2 Answers

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;
like image 75
Nighteen Avatar answered Oct 07 '22 21:10

Nighteen


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
like image 34
Mi-La Avatar answered Oct 07 '22 23:10

Mi-La