Defining a constant

What is the recommanded procedure ?
From my "reading" :
1
2
3
const int UNSET { 0 };
or
#define UNSET 0 

I may be mixing apples and oranges here
TIA
Michel Chassey
It depends what language you use.
#define is the old C way
const or constexpr are C++
It's not apples to oranges, but using #define is simply the older, "C" way of doing things.

using
const int UNSET { 0 };
or
constexpr int UNSET { 0 };
is definitely the modern, "C++" way of doing it. It's type safe, and will be optimized away just as easily as the old #define way.

Side note: Some people will argue that ALL_CAPS variable should be reserved for #defined macros only. I personally tend to follow this, but there's no set rules that everyone agrees on, so do what works best for you.
Side note: Some people will argue that ALL_CAPS variable should be reserved for #defined macros only.

While this is true with C, especially since a constant in C is a #defined macro, in C++ many people use all caps for global constants as well as macros (although in C++ macros are frowned upon in most cases).

and I disagree, because about 3/4 of the constants I use are specifically lower case in 'the world'. EG e = 2.71828 ... it is never E.

#define is not just old, it can cause problems from time to time. Best to not use macros at all without a very good reason to do so in modern c++. There are one or two uses for them in things like debugging that I am unaware of a replacement for; I think there are some extensions etc that you can print what routine you are currently in for example to create a generic 'where did it really crash' print statement macro.
Last edited on
because about 3/4 of the constants I use are specifically lower case in 'the world'. EG e = 2.71828 ... it is never E.

IMO, having a global constant with a single letter name is a very bad practice.


For that specific point, I would suggest a name involving "Euler's Number". I don't usually have to deal with e though, since I feel like a lot of math doesn't force you to use it directly (as in, for non-exponent operations, of course there are exceptions), or you use std::exp.

One of the annoyances with the Wolfram language is just that -- reserved single-letter names.
Last edited on
Hello,
From what is said here, macros are bad. I would be writing functions
instead of macros.

More digging is required before I decide on const and constexpr.
I'm getting there.
const std::string wow { "OMG" };

Thanks,
Michel Chassey
Ps lots of "reading" in these posts, folks :)
@mycuser

Hi Michael,

There some differences between const and constexpr:

With constexpr, it's constness cannot be cast away, so it's value really is set in stone at compile time;

Also, constexpr can be an actual expression, as in:

1
2
double constexpr PI = acos(-1.0);
double constexpr DegreeToRadian = PI / 180.0;


One can also have constexpr functions and constructors, I guess you can read up about them.
the trouble with using a nice big fat name is it screws up the math.
instead of x = y/e you get x = y/EULERS_NUMBER which isnt so bad in a 2 term equation but when you get a hairy long equation, it explodes into a mess that does not remotely resemble the original recognizable textbook form in a hurry.

Honestly I haven't used e much either, just a few places. It was easier to use as an example than aerospace jargon letters like a (which is a variable but still, you use 1 letter so it matches the textbook form equations).

We did try naming and spelling them out for a period. It was just unmanageable.


Last edited on
I agree with jonnin: Use a meaningful name, unless one wants to match the variables shown in the technical documentation's mathematical equation.

Obviously it pays to document where the equations come from, and spell out confusing things. For example: in Geodesy e means eccentricity, not Eulers constant.

One solution could be to put the constants into a namespace.

1
2
3
4
5
namespace math_constants
{
	const double pi = 3.14;
	const double e = 2.72;
};


If you only use a constant once or twice and is worried that the short names might clash with other variables you can just use the full name.

1
2
3
4
void print_fact()
{
	std::cout << "The value of π is approximately " << math_constants::pi << ".\n";
}


If you happen to use the constants a lot within a file or within a function you can use using namespace inside that file or function which will allow you to use the constants without having to use the namespace name.

1
2
3
4
5
6
7
8
9
10
11
using namespace math_constants;

double circle_area(double r)
{
	return pi * r * r;
}

double circle_perimeter(double r)
{
	return 2 * pi * r;
}
Last edited on
I am talking about global constants, not local variables or local constants. IMO, constant global variables should have meaningful names, except in very rare circumstances, even if you have to break those large calculations into sub-calculations in order to keep your sanity.

Now if you're writing code for a specific "locale" where otherwise meaningless names have meaning then by all means use those names. However you would still be advised to document what those names actually mean.

However in most situations you would be advised against using single letter names except in very local scopes.

Even using acronyms should usually be avoided when writing code for general consumption since there may be multiple meanings for any one acronyms depending on content.


As an aside, I just discovered clang++ can deal with Unicode identifiers directly, so now I can have Greek characters for variable names. I suppose now it is an issue if the code can only be compiled with clang++. OTOH with g++ it seems isn't standard compliant on this particular point.

g++ can do it too, but involves running a shell script to convert the Unicode. I find it untenable to have multiple files: MyClass.hpp and MyClassUTF.hpp and 2 cpp files as well.

https://gcc.gnu.org/wiki/FAQ#What_is_the_status_of_adding_the_UTF-8_support_for_identifier_names_in_GCC.3F
you can read up about them.
"Read on" TheIdeasMan says "Read on..." :)

Michel Chassey
THAT has been a long time coming. Symbolic code, once fully supported, will be a boon to a lot of coders out there, while adding creative new ways to make code even harder to read in the hands of the gremlins.

mycuser wrote:
"Read on" TheIdeasMan says "Read on..." :)


Well perhaps later then :+)

The thing is, at least now you know that this thing in general exists, which is a whole lot better than not knowing. So some time in the future you could say: "I know about the basic idea of constexpr, but there can also be constexpr functions and constructors, so I will read up about them now"

I find this idea useful for any system whether it be software or anything else. It is good to have an overview knowledge of all the things the system can do, as opposed to a detailed knowledge of say 5% and no knowledge of the rest. The latter is where the majority of computer users reside.

I see it all the time, like a typist not knowing and not interested in learning about paragraph numbering, but then complains about how much work there is to do when the Engineer completely reorders chapters and paragraphs in an entire document.
1
2
3
4
namespace math_constants
{
	const double e = 2.72;
};

Yes, that is elegant. I've done this before in the past in projects, but it escaped my mind...
> now I can have Greek characters for variable names.

Most coding guidelines require that identifiers (and comments) must be in English
(or a dialect of English; for instance, American is widely used.)


C++14 has variable templates. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <type_traits>
#include <iostream>
#include <iomanip>

namespace maths
{
    template < typename T >
       using floating_point = typename std::enable_if< std::is_floating_point_v<T>, T >::type ;

    template < typename T = double > constexpr floating_point<T> pi = T(3.1415926535897932384626433) ;
    template < typename T = double > constexpr floating_point<T>  e = T(2.7182818284590452353602874) ;
}

int main()
{
    std::cout << std::fixed << std::setprecision(16)
              // << maths::pi<int> << '\n' // *** error: not a floating point type ***
              << maths::pi<> << '\n' // pi<double>
              << maths::e<float> << '\n' ;
}

http://coliru.stacked-crooked.com/a/e0e7f467a356dd5c
Topic archived. No new replies allowed.