====== Using C++ "constexpr" to replace #define ======
In C, the only way to define symbolic constants was to use ''#define''---in effect, a parameter-less macro. This is often used to specify the value of a symbolic constant in one place, so it can be used later in one or more other places, to declare the size of an array, e.g.
#define kMyArraySize 100
...
double MyArray[kMyArraySize];
C++ introduced the ''const'' keyword, which is a big improvement because it allows you to declare //strongly-typed// symbolic constants, e.g.
const int MyArraySize = 100;
The expression to the right of the ''='' (assignment operator, used as an initialization operator in this context) in such a ''const'' declaration is computed at compile-time by the C++ compiler, and as a result can be used in an array-size declaration like this:
double MyArray[kMyArraySize];
Within a class declaration, it's necessary to declare such compile-time ''const'' objects ''static'', e.g.
class MyClass
{
static const int kArraySize = 100;
...
double array[kArraySize];
};
I'm not entirely sure why this is, because if the declared constant is indeed constant, defined at compile time, there would never be a need for it to be treated as an instance member. However, the people who write the compilers make the rules, and this is simply the rule.
In my original //VanillaJuceAudioProcessor// class declaration, I used an awkward combination of a ''#define'' for a fixed array size, plus an ''enum'' declaration for a constant used in the constructor, like so:
#define kNumberOfPrograms 128
class VanillaJuceAudioProcessor
: public AudioProcessor
, public ChangeBroadcaster
{
public:
enum { maxNumberOfVoices = 16 };
...
private:
SynthParameters programBank[kNumberOfPrograms];
...
};
VanillaJuceAudioProcessor::VanillaJuceAudioProcessor()
: currentProgram(0)
{
...
for (int i = 0; i < maxNumberOfVoices; ++i)
synth.addVoice(new SynthVoice());
...
}
In the first case I was just using ''#define'' the way I always had in C, and in the second case I was following an example I'd seen somewhere, but the truth was I just hadn't figured out how to do it properly in C++, which is
class VanillaJuceAudioProcessor
: public AudioProcessor
, public ChangeBroadcaster
{
...
private:
static const int kNumberOfPrograms = 128;
static const int kNumberOfVoices = 16;
...
SynthParameters programBank[kNumberOfPrograms];
...
};
The [[wp>C++11|C++11]] standard introduced a more powerful new keyword ''constexpr'', which can be used to define complex expressions to be evaluated at compile-time, and which is particularly useful with templates. I hunted across the web to find any evidence that ''constexpr'' should be used for ordinary constant-declarations, without success, so I'm not sure I understand Jules's admonishment "NEVER use a #define for a constant!! Use constexpr!".
I did find one instance in the JUCE source code, where ''constexpr'' was used in this way, in the file ''juce_android_OpenSL.cpp'':
class SLRealtimeThread
{
public:
static constexpr int numBuffers = 4;
...
};
Since the class //SLRealtimeThread// is not a template class, I have to assume that ''constexpr'' is trivially equivalent to ''const'' in this case, and that Jules was using "constexpr" somewhat generically as a short form of "''const'' expression''.