Let me start by stating my intent. In the olden (C++) days, we would have code like:
class C
{
public:
enum {SOME_VALUE=27};
};
Then we could use SOME_VALUE
throughout our code as a compile time constant and wherever the compiler would see C::SOME_VALUE
, it would just insert the literal 27.
Now days, it is seems more acceptable to change that code to something like:
class C
{
public:
static constexpr int SOME_VALUE=27;
};
This looks much cleaner, gives SOME_VALUE
a well defined type and seems to be the preferred approach as of C++11. The (unforseen at least for me) problem is that this also causes scenarios where SOME_VALUE
needs to be made external. That is, in some cpp file somewhere, we need to add:
constexpr int C::SOME_VALUE; // Now C::SOME_VALUE has external linkage
The cases that cause this seem to be when const references to SOME_VALUE
are used, which happens quite often in C++ Standard Library code (See the example at the bottom of this question). I am using gcc 4.7.2 as my compiler by the way.
Due to this dilemma, I am forced to revert back to defining SOME_VALUE
as an enum (i.e., old school) in order to avoid having to add a definition to a cpp file for some, but not all of my static constexpr member variables. Isn't there some way to tell the compiler that constexpr int SOME_VALUE=27
means that SOME_VALUE
should be treated only as a compile time constant and never an object with external linkage? If you see a const reference used with it, create a temporary. If you see its address taken, generate a compile time error if that's what's needed, because it's a compile time constant and nothing more.
Here is some seemingly benign sample code that causes us to need to add the definition for SOME_VALUE
in a cpp file (once again, tested with gcc 4.7.2):
#include <vector>
class C
{
public:
static constexpr int SOME_VALUE=5;
};
int main()
{
std::vector<int> iv;
iv.push_back(C::SOME_VALUE); // Will cause an undefined reference error
// at link time, because the compiler isn't smart
// enough to treat C::SOME_VALUE as the literal 5
// even though it's obvious at compile time
}
Adding the following line to the code at file scope will resolve the error:
constexpr int C::SOME_VALUE;
See Question&Answers more detail:os