Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Pros and cons to everything, depending on usage:</p> <ul> <li>enums <ul> <li>only possible for integer values</li> <li>properly scoped / identifier clash issues handled nicely</li> <li>strongly typed, but to a big-enough signed-or-unsigned int size over which you have no control (in C++03)</li> <li>can't take the address</li> <li>stronger usage restraints (e.g. incrementing - <code>template &lt;typename T&gt; void f(T t) { cout &lt;&lt; ++t; }</code> won't compile)</li> <li>each constant's type taken from the enclosing enum, so <code>template &lt;typename T&gt; void f(T)</code> get a distinct instantiation when passed the same numeric value from different enums, all of which are distinct from any actual f(int) instantiation.</li> <li>even with typeof, can't expect numeric_limits to provide useful insight</li> <li>the enum's typename may appear in various places in RTTI, compiler messages etc. - possibly useful, possibly obfuscation</li> </ul></li> <li>consts <ul> <li>properly scoped / identifier clash issues handled nicely</li> <li>strong, single, user-specified type</li> <li>One Definition Rule complications</li> </ul></li> <li>defines <ul> <li>"global" scope / more prone to conflicting usages, which can produce hard-to-resolve compilation issues and unexpected run-time results rather than sane error messages; mitigating this requires: <ul> <li>long, obscure and/or centrally coordinated identifiers, and access to them can't benefit from implicitly matching used/current/Koenig-looked-up namespace, namespace aliases etc.</li> <li>use of all uppercase characters is generally required and reserved for preprocessor defines (an important guideline for enterprise scale preprocessor usage to remain manageable, and which 3rd party libraries can be expected to follow), observation of which implies migration of existing consts or enums to defines involves a change in capitalisation (and hence affects client code). (Personally, I capitalise the first letter of enums but not consts, so I'd be hit here anyway - maybe time to rethink that.)</li> </ul></li> <li>more compile-time operations possible: string literal concatenation, stringification (taking size thereof) <ul> <li>downside is that given <code>#define X "x"</code> and some client usage ala <code>"pre" X "post"</code>, you're in trouble if you want or need to make X a runtime-changeable variable rather than a constant, whereas that transition is easier from a <code>const char*</code> or <code>const std::string</code> given they already force the user to incorporate concatenation operations.</li> </ul></li> <li>can't use sizeof directly on a defined numeric constant</li> <li>untyped (GCC doesn't warn if compared to unsigned)</li> <li>some compiler/linker/debugger chains may not present the identifier, so you'll be reduced to looking at "magic numbers" (strings, whatever...)</li> <li>can't take the address</li> <li>the substituted value need not be legal (or discrete) in the context where the #define is created, as it's evaluated at each point of use, so you can reference not-yet-declared objects, depend on "implementation" that needn't be pre-included, create "constants" such as <code>{ 1, 2 }</code> that can be used to initialise arrays, or <code>#define MICROSECONDS *1E-6</code> etc. (<em>definitely</em> not recommending this!)</li> <li>some special things like <code>__FILE__</code> and <code>__LINE__</code> can be incorporated into the macro substitution</li> </ul></li> </ul> <p>As a general rule, I use consts and consider them the most professional option for general usage (though the others have a simplicity appealing to this old lazy programmer).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload