And once again about unique constants

After reading the article “Calculate the circumference” , which, in general, extremely amused me with its style, and learning something new for myself, I began to doubt somewhat the sufficient details of the proposed information. Still, there are a lot of compilers, a lot of systems, too, and the article is somehow inspired by Windows and Visual Studio (as IMHO).

We will talk about examples after the removal of the "mysterious" constant outside the function. Since the truth about this action is worse than told by a cunning professor . Note: I tested everything exclusively "on hand":
  • OS X 10.10 with gcc 4.9.2 and clang 3.5 / 3.6
  • Ubuntu 14.10 with clang 3.5
  • Windows with MinGW-w64-32 and gcc 4.9.2

I do not exclude something even more extraordinary under other systems. I would be glad if someone tells me about them.

Is it true that constexpr can do anything?

A scientific student, having graduated from institute and having come to work as a C ++ developer (say, for the main desktop systems, Linix, OS X, Windows), learns that everyone at the company has already switched to C ++ 11 compatible compilers. Pleased with the ability to write easier and shorter, the hero writes in one of the header files like this:

constexpr char sin_tables[4096] { /* Заполните значениями, если очень хочется */};

About an hour after a commit from a neighboring department, which is testing builds under OS X, a bewildering cry is heard that the binary is bad. Everything is simple, unlike Visual C ++ (certain new versions), neither clang (3.5, 3.6) nor gcc (4.8, 4.9) rely on such undefined behavior (for some reason, the Microsoft compiler stopped seeing a regular variable with internal linking in constexpr and did, however, a good deed), and we got a duplication of our array.

An example :
Hidden text
An example written on the knee:


#include "h.h"
void printSin1() {
	for (auto &e : sin_tables)
		printf("%f\n", e);
int main() {


#include "h.h"
void printSin2() {
	for (auto &e : sin_tables)
		printf("%f\n", e);


constexpr float sin_tables[4096] { /* ... */};
void printSin1();
void printSin2();

For those who are too lazy to collect :

Hidden text

If you think that the specific work of compilers on OS X is to blame, then I hasten to assure you, it is also in Ubuntu, and in the environment of MinGW. This is a global feature of the clang and gcc compilers ...

And if you try the old "proven" method?

Here is a misfortune, our young programmer thought. Maybe write a hack for these penguin poppies. No sooner said than done.

#if !defined(CONST_UNIQUE)
	#if defined(MSVC)
		#define CONST_UNIQUE constexpr
		#define CONST_UNIQUE extern __attribute__((weak)) constexpr

Everything works, everything is going. But after a couple of minutes new cries come from the same room: a non-working commit, a buildbot threw an error, what are you doing ?! The problem, again, is not unusual. Clang, although making attempts to implement all non-standard in gcc, has never been fully compatible and is unlikely to be. Well, therefore, in special cases of using this attribute, a surprise will be waiting for us (well, how could it be without this).

CONST_UNIQUE int A = 137; // gcc OK, clang OK
CONST_UNIQUE int B = A+1; // gcc OK, clang OK
std::array loveClang; // gcc OK, clang FAIL

./file.cpp:21:17: error: non-type template argument is not a constant expression
std::array loveClang;

That's all right, as this man even dared to write a hack, and send it to the trunk. History is silent that in particularly “understanding” cases MinGW can use the hack selectany, instead of weak, as a more Windows-like one. However, he also will not save from the above error.

And what to do? And what to do?

As my personal experience shows, magic constants are usually specific to some block or program module. Clogging the global namespace with them is rare enough, and so now no one will forbid you to write:


class MyClass {
	/* ... */
	static constexpr float m_pi {3.14};
	/* ... */


constexpr float MyClass::m_pi;

That this will completely solve the question of the readability of the constants, with their visibility and forbidden propagation. With the link, yes, the question remains open, but this is more than nothing (especially considering the standard implementation). To avoid accusations of plagiarism, I add a link here , where similar is also described.

However, do not you think that the above is a serious fixation on a very small problem? In reality, everyone understands:
  • that constants like pi are in headers (and often even in microcontrollers);
  • that if a magic constant is needed, it is often integer than fractional, which means it is most likely optimized by the compiler (far-fetched, yes);
  • for something constant and big, it’s not so unfortunate to write a couple of extra lines (earlier, for example, I used static const in classes or extern, if necessary, in other places);
  • that constants with the same values, but with different names (aliases), and without weak, the compiler can optimize in one in some cases.

Also popular now: