Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding static constexpr member variables

Tags:

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 about cond_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 and clang-3.6.

like image 242
Titas Chanda Avatar asked Dec 02 '15 21:12

Titas Chanda


People also ask

Are constexpr variables static?

A constexpr variable must have static storage at some point, it's baked in when the program is compiled.

What is a static member variable?

A variable declared static within a module (but outside the body of a function) is accessible by all functions within that module. However, it is not accessible by functions from other modules. static members exist as members of the class rather than as an instance in each object of the class.

Why does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.

Can a member function be constexpr?

const can only be used with non-static member functions whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.


1 Answers

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.

like image 122
101010 Avatar answered Sep 23 '22 03:09

101010