I have a class for local use only (i.e., its cope is only the c++ file it is defined in)
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
All the code reside in the same c++ file. When compiling using VS on windows, there is no problem at all.
However, when compiling on Linux I get the undefined reference
error only for the second statement.
Any suggestions?
std::min<int>
's arguments are both const int&
(not just int
), i.e. references to int
. And you can't pass a reference to A::MY_CONST
because it is not defined (only declared).
Provide a definition in the .cpp
file, outside the class:
class A {
public:
static const int MY_CONST = 5; // declaration
};
const int A::MY_CONST; // definition (no value needed)
// initialize static constants outside the class
class A {
public:
static const int MY_CONST;
};
const int A::MY_CONST = 5;
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error:
// undefined reference to `A::MY_CONST`
}
To explain what's happening here:
You declared static const
integer inside class, this "feature" is here to be able to use it as constant expression,i.e. for local array size, template non-type parameters, etc.. If compiler wants to use this constant expression it must be able to see it's value in that translation unit.
9.5/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.19). 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.
odr-used means to form reference to that variable or take it's address.
std::min
takes it's parameters by reference, so they are odr-used.
Solution:
Define it!
class A
{
static const int a = 5;
};
const int A::a; //definition, shall not contain initializer
I am having a very strange situation
template<class T> class Strange {
public:
static const char gapchar='-';
};
template<class T> void Strange<T> method1 {
char tmp = gapchar;
}
template<class T> void Strange<T> method2 {
char tmp = gapchar;
}
I include the above class, it has been working for several years.
I added another method, essentially the same signature and just reading the gapchar.
I got undefined error only for the third method, even I am using all three methods.
Then I changed the way I initialize the static variable by
not initializing in the class definition:
static const char gapchar;
template<class T> const char Strange<T>::gapchar='-';
This solved the problem. I could not figure out why the old way of
initializing int or char type (the only two types allowed) inside the class
definition section stop working for only one of the methods but not others.
You can also save the const value to a local variable.
class A {
public:
static const int MY_CONST = 5;
};
void fun( int b ) {
int j = A::MY_CONST; // no problem
int k = std::min<int>( A::MY_CONST, b ); // link error: undefined reference to `A::MY_CONST`
int l = std::min<int>( j, b); // works
}