📜 ⬆️ ⬇️

And once again about the unique constants

After reading the article “Calculate the length of a circle” , which, in general, extremely amused me with its style, and having learned something new for myself, I began to somewhat doubt the sufficient detail of the proposed information. Still, there are quite a few compilers, there are also quite a few systems, and the article is somehow inspired by Windows and Visual Studio (on the rights of IMHO).

The discussion will deal with examples after taking the “mysterious” constant beyond the limits of the function. Since the truth about this action is worse than that told by a cunning professor . Note: I tested everything exclusively on the ones at hand:

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

Is constexpr true, can everything?


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

constexpr char sin_tables[4096] { /*  ,    */}; 

About an hour after the commit from a neighboring department that tests builds under OS X, a bewildered cry is heard that the binary is very poplough. Everything is simple, unlike Visual C ++ (certain new versions), neither clang (3.5, 3.6) nor gcc (4.8, 4.9) rely on such unspecified behavior (the Microsoft compiler for some reason stopped seeing the normal variable with internal linking in constexpr and did, however, a good deed), and we received a duplication of our array.
')
Example :
Hidden text
Example written on the knee:

a.cpp

 #include <cstdio> #include "hh" void printSin1() { for (auto &e : sin_tables) printf("%f\n", e); } int main() { printSin1(); printSin2(); } 

b.cpp

 #include <cstdio> #include "hh" void printSin2() { for (auto &e : sin_tables) printf("%f\n", e); } 

hh

 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 MinGW environment. This is a global feature of the clang and gcc compilers ...

And if you try the old "proven" way?


That's the same attack, considered our young programmer. Maybe write a hack for these penguin-makovodov. No sooner said than done.

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

Everything works, everything is going. But after a couple of minutes, new cries are heard from the same room: a non-working commit, a buildbot threw a mistake, what are you doing ?! Again, the problem is not unusual. Clang, although trying to implement everything 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 await us (well, of course without it).

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


 ./file.cpp:21:17: error: non-type template argument is not a constant expression std::array<int, A> loveClang; ^ 

That's all right, as this man in general dared to write a hack, and send it to the trunk. History is silent that in especially "understanding" cases in MinGW, the hack can be selectedany, instead of weak, as more Windows-like. However, he will not save from the above error either.

And what to do? And how to be?


As my personal experience shows, magic constants are usually specific for a certain block or module of a program. It is quite rare to litter the global namespace with them, so now nobody will forbid you to write:

MyClass.h

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

MyClass.cpp

 constexpr float MyClass::m_pi; 

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

However, do not you think that the above is a serious loop on a very small problem? In reality, everyone understands:

Source: https://habr.com/ru/post/254077/


All Articles