Understanding static constexpr member variables
According to the standard 9.4.2/p3 Static data members [class.static.data] (Emphasis Mine):
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.20). 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.
As M.M earlier explained in the comments ostream::operator<<(ostream&, const complex<T>&)
passes by reference so value is considered odr-used in the program. Thus, as the wording above dictates you have to provide a definition.
Now as you’ve already found out fundamental types are passed by value, that it is why no definition required.
Titas Chanda
Senior Research Fellow, Quantum Information and Computation, Harish-Chandra Research Institute, Chhatnag Road, Jhunsi, Allahabad - 211 019, Uttar Pradesh, India.
Updated on July 27, 2022Comments
-
Titas Chanda almost 2 years
I have some confusions regarding
static constexpr
member variables in C++11.In first.hpp
template<typename T> struct cond_I { static constexpr T value = 0; }; // specialization template<typename T> struct cond_I< std::complex<T> > { static constexpr std::complex<T> value = {0,1}; };
In main() function
cout << cond_I<double>::value << endl; // this works fine cout << cond_I< complex<double> >::value << endl; // linker error
However if I add the following line to
first.hpp
everything works fine.template<typename T1> constexpr std::complex<T1> cond_I< std::complex<T1> >::value;
What I understand (I may be wrong) is, that
cond_I< std::complex<double> >::value
needs a definition, but in the previous case it only has the declaration. But then what aboutcond_I<double>::value
? Why it does not require a definition?Again, in another header file,
second.hpp
, I have:In second.hpp
// empty struct template<typename T> struct eps { }; // special cases template<> struct eps<double> { static constexpr double value = 1.0e-12; }; template<> struct eps<float> { static constexpr float value = 1.0e-6; };
In this case, following codes works perfectly without any definition of
eps<>::value
.In main() function
cout << eps<double>::value << endl; // works fine cout << eps<float>::value << endl; // works fine
Can someone please explain me the different behaviors of
static constexpr
member variables, in these scenarios?These behaviors are also the same for
gcc-5.2
andclang-3.6
.