This question is closely related to a question that was previously asked here.
In order for the Visual Studio 2010 C++ debugger to resolve in-class-initialized const variables, a global definition for the variable must be supplied.
e.g.
Here is the class definition:
class B{
public:
static const int m_b=100;
};
Here is the global scope definition of the member:
const int B::m_b;
Without the global definition the code works but the debugger cannot see m_b within B's methods.
However, this leads to another problem. In non-trivial header file inclusion arrangements (full code given below), Visual Studio produces this link error:
error LNK2005: "public: static int const B::m_b" (?m_b@B@@2HB) already defined in a.obj
1>a.exe : fatal error LNK1169: one or more multiply defined symbols found
However GCC compiles, links, and runs the code successfully.
Here is the code in question:
file a.cpp:
#include <iostream>
#include "a.h"
const int B::m_b;
int main()
{
B b;
std::cout << b.m_b;
return 0;
}
file a.h:
#pragma once
#include "b.h"
file b.cpp:
#include "b.h"
file b.h:
#pragma once
class B {
public:
static const int m_b = 100;
};
Here are the linker options (default VS10 console program):
/OUT:"a.exe"
/NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib"
/MANIFEST
/ManifestFile:"Debug\a.exe.intermediate.manifest"
/ALLOWISOLATION
/MANIFESTUAC:"level='asInvoker' uiAccess='false'"
/DEBUG
/PDB:"Debug\a.pdb"
/PGD:"Debug\a.pgd"
/TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
Here are the compiler options (default VS10 console program):
/ZI /nologo /W3 /WX- /Od /Oy- /D "_MBCS" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t
/Zc:forScope /Fp"Debug\sndbx.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd
/analyze- /errorReport:queue
Again, this builds, links, and runs successfully with GCC ( g++ a.cpp b.cpp ). The code I've supplied is complete so it can be copied, pasted, and run.
According to what clang will accept, the static const variable initialisation must happen in the definition rather than the declaration.
Therefore in your header you want this:
And then the definition in your cpp should be like this:
You shouldn't put non-template definitions of data in header files, because you will get multiple definition errors at link time. Whether the variable is a member variable or a static member variable or a const static member variable doesn't change this at all.
Put the definition in exactly one compilation unit, just like you would for any other singleton.
This actually looks like a Visual C++ bug. It would have helped considerably if you had shown the complete error message, namely
The symbol would not be defined anywhere in b.obj if the compiler were working right.
Furthermore, attempting to use
__declspec(selectany)
tells us that the compiler knows this is not a definition:Finally, Visual C++ clearly is defining the symbol (incorrectly):
R:\16404173>dumpbin /symbols b.obj Microsoft (R) COFF/PE Dumper Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved.
Furthermore, we see that it is marked as
selectany
already. But in the compilation unit with the actual definition:The
(pick any)
annotation is gone. Which is proper, this is an authoritative definition of the variable.It's wrong for the variable to appear in
b.obj
at all. The compiler makes the simple case (initialization inside header file) work by using theselectany
annotation, but this hackish workaround falls apart when a real definition is provided.Finally, adding
__declspec(selectany)
on the real definition, in a.cpp, works around the link error. But I'm afraid the symbol will still be optimized away by the linker and not available during debugging. You can temporarily use the/OPT:NOREF
to avoid this (but it will bloat your executable, so turn that option off again before shipping).