Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Static Const Member Variable Usage

Say that I have a class that requires a few constants to function. Several member functions require use of these constants. Use of #define is frowned upon since it can cause collisions. The constants are hex patterns of 8 or 16 bits and are stored as uint8_t or uint16_t. These constants also don't change from instance to instance of the class, and therefore memory (albeit very little memory) can be saved by having only one copy of the constants.

Is there anything improper, or perhaps of better way of accomplishing the above instead of simply doing something like the following:

// mycode.h // ....... class myclass { private:   static const uint16_t kMyClassConstant_ = 0xBEEF; // ....... }; 

Thanks in advance for the help.

like image 274
It'sPete Avatar asked Jun 12 '13 02:06

It'sPete


People also ask

Can static members be const?

A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.

What is the use of static const in C?

“static const” is basically a combination of static(a storage specifier) and const(a type qualifier). The static determines the lifetime and visibility/accessibility of the variable.

Can we use static const in C?

const means that you're not changing the value after it has been initialised. static inside a function means the variable will exist before and after the function has executed. static outside of a function means that the scope of the symbol marked static is limited to that . c file and cannot be seen outside of it.

Is it static const or const static?

They mean exactly the same thing. You're free to choose whichever you think is easier to read. In C, you should place static at the start, but it's not yet required.


2 Answers

Given your description of the situation, I'd say using static const members is a good approach. In C++11 you may want to change it into static constexpr to emphasize it's a compile-time constant, although nothing will effectively change as a result of that.

If you refer to myclass::kMyClassContant_ somewhere in the code in a way that is relevant under the one-definition-rule (odr), esp. in contexts that require a reference (including const-reference), the compiler will complain that there is no definition of the constant. Merely declaring and initializing it inside the class isn't sufficient in this case. This may force you to separate declaration and definition:

// mycode.h class myclass { private:   static const uint16_t kMyClassConstant_; };  // mycode.cpp const uint16_t myclass::kMyClassConstant_ = 0xBEEF; 

To avoid the trouble of maintaining separate declarations and definitions, some people prefer declaring an inline constexpr function instead of an actual variable:

// mycode.h class myclass { private:   static constexpr uint16_t kMyClassConstant_()   { return 0xBEEF; } }; 

This is a correct work-around for many of the odr-related problems, and it does not cause any loss in performance. Whether it is really useful depends on how much of a burden it is to maintain separate declarations and definitions of an ordinary static constant. If you expect your constants to never change as your code evolves, using ordinary static constants with separate definitions is preferable. But if you modify the definitions of the constants frequently, having to re-compile the definition file and re-link it to all relevant parts of the project may make you consider the function-based solution above as a better alternative.

A final comment on the data type: Forcing it into 16 bits using std::uint16_t can be useful if you need to store lots of these values in compact form. Otherwise, the actual size may not really matter, in which case std::uint_fast16_t (which may be larger than 16 bits) may be better.

like image 76
jogojapan Avatar answered Sep 23 '22 16:09

jogojapan


You could use type traits to implement this:

#include <type_traits>  class myclass { private:   typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant;    // ... }; 

used as myclass::kMyClassConstant::value.

This shows the purpose of implementing an integral constant and prevents you from accidentaly taking an address of the constant.

like image 30
Jan Herrmann Avatar answered Sep 23 '22 16:09

Jan Herrmann