template <class T, int m>
class A {
public:
static const T param = m;
T value;
A(const T &value, const T &dummy = T()) : value(value) {}
};
// Works with this
// template <class T, int m>
// const T A<T, m>::param = m;
//gotta define it here!
template <class T, int m>
const T A<T, m>::param;
template <class T, int m>
A<T, m> operator +(const A<T, m> &a, const A<T, m> &b) {
if (a.param != b.param) exit(1);
// Works if I replace a.param with 0
return A<T, m>(a.value + b.value, a.param);
}
int main() {
A<int, 2> v = A<int, 2>(1) + A<int, 2>(2);
std::cout << v.value << std::endl;
return 0;
}
from here
If a static data member is of const integral or const enumeration type, you may specify a constant initializer in the static data member's declaration. This constant initializer must be an integral constant expression. Note that the constant initializer is not a definition. You still need to define the static member in an enclosing namespace.
In the cases that is working, the compilers are being non-compliant. Microsoft is non-compliant cuz Microsoft is almost never compliant, the g++ with -O2 is kinda funny, but in either case you've got no definition!
Edit: As a rule of thumb, I always define my static constant member variables outside of the class because then I never have to remember it. In this case, class A would be invalid if T was anything other than an integral type, such as a float. So rather than do any patterns around the exception, I tend to just stick with my patterns around the rule.