I\'d like to define a constant char* in my header file for my .cpp file to use. So I\'ve tried this:
private:
static const char *SOMETHING = \"sommething\";
There is a trick you can use with templates to provide H file only constants.
(note, this is an ugly example, but works verbatim in at least in g++ 4.6.1.)
(values.hpp file)
#include <string>
template<int dummy>
class tValues
{
public:
static const char* myValue;
};
template <int dummy> const char* tValues<dummy>::myValue = "This is a value";
typedef tValues<0> Values;
std::string otherCompUnit(); // test from other compilation unit
(main.cpp)
#include <iostream>
#include "values.hpp"
int main()
{
std::cout << "from main: " << Values::myValue << std::endl;
std::cout << "from other: " << otherCompUnit() << std::endl;
}
(other.cpp)
#include "values.hpp"
std::string otherCompUnit () {
return std::string(Values::myValue);
}
Compile (e.g. g++ -o main main.cpp other.cpp && ./main) and see two compilation units referencing the same constant declared in a header:
from main: This is a value
from other: This is a value
In MSVC, you may instead be able to use __declspec(selectany)
For example:
__declspec(selectany) const char* data = "My data";
To answer the why question, integral types are special in that they are not a reference to an allocated object but rather values that are duplicated and copied. It's just an implementation decision made when the language was defined, which was to handle values outside the object system and in as efficient and "inline" a fashion as possible.
This doesn't exactly explain why they are allowed as initializors in a type, but think of it as essentially a #define
and then it will make sense as part of the type and not part of the object.
If you're using Visual C++, you can non-portably do this using hints to the linker...
// In foo.h...
class Foo
{
public:
static const char *Bar;
};
// Still in foo.h; doesn't need to be in a .cpp file...
__declspec(selectany)
const char *Foo::Bar = "Blah";
__declspec(selectany)
means that even though Foo::Bar
will get declared in multiple object files, the linker will only pick up one.
Keep in mind this will only work with the Microsoft toolchain. Don't expect this to be portable.