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.
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 intostatic 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:To avoid the trouble of maintaining separate declarations and definitions, some people prefer declaring an inline constexpr function instead of an actual variable:
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 casestd::uint_fast16_t
(which may be larger than 16 bits) may be better.Since C++17, we have access to
inline
variables, which take care of the odr-related problems. Several options:Or, if it can be marked
constexpr
(like in this case):Which can be simplified to:
Because in C++17
constexpr
impliesinline
forstatic
data members.You could use type traits to implement this:
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.