もう一度、一意の定数について

一般的に、そのスタイルに非常に面白がって、自分にとって新しいことを学んだ記事「円周を計算する」を読んだ後、私は提案された情報の十分な詳細をいくらか疑い始めました。 それでも、多くのコンパイラ、多くのシステムがあり、記事は何らかの形でWindowsとVisual Studio(IMHOとして)に触発されています。



関数の外側の「神秘的な」定数を削除した後の例について説明します。 この行動についての真実はcな教授が語るより悪いからです。 注:すべてを「手元」で排他的にテストしました。



私は他のシステムの下でさらに特別な何かを除外しません。 誰かが彼らについて教えてくれたら嬉しいです。



constexprは本当にすべてに対応していますか?



インスティテュートを卒業し、C ++開発者(たとえば、メインデスクトップシステム、Linix、OS X、Windows)として働くようになった学生は、会社の全員がすでにC ++ 11互換コンパイラに切り替えたことを知ります。 より簡単に、そしてより短く書く能力に満足して、ヒーローは次のようなヘッダーファイルの1つに書き込みます:



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





OS Xでビルドをテストしている隣接部門からのコミットの約1時間後、バイナリが不良であるという戸惑う叫び声が聞こえます。 Visual C ++(特定の新しいバージョン)とは異なり、clang(3.5、3.6)もgcc(4.8、4.9)もこのような未定義の動作に依存していません(何らかの理由で、Microsoftコンパイラーはconstexprの内部リンクを含む通常の変数の表示を停止しました)そして、しかし、善行を行いました)、私たちは私たちの配列の複製を得ました。





非表示のテキスト
膝に書かれた例:



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); }
      
      





えー



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







収集するのが面倒な人のために



非表示のテキスト








OS Xでのコンパイラの特定の作業が非難であると思われる場合は、お急ぎください。UbuntuおよびMinGWの環境にもあります。 これは、clangおよびgccコンパイラのグローバル機能です...



そして、あなたが古い「証明された」方法を試してみると?



ここに不幸があります、私たちの若いプログラマは考えました。 たぶん、これらのペンギンポピーのハックを書いてください。 すぐに言ってやった。



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





すべてが機能し、すべてが進んでいます。 しかし、数分後、同じ部屋から新しい叫び声が出てきました。コミットが機能していない、ビルドボットがエラーを投げました、何をしているのですか?! ここでも、問題は珍しいことではありません。 Clangは、gccですべての非標準を実装しようと試みていますが、完全に互換性があることはなく、そうなる可能性は低いです。 したがって、この属性を使用する特殊なケースでは、驚きが待っています(これがないとどうなるでしょう)。



 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; ^
      
      





この男はあえてハックを書き、それをトランクに送信したので、大丈夫です。 特に「理解」している場合に、MinGWが弱いWindowsのようなハックselectanyを使用できるという歴史はありません。 ただし、彼は上記のエラーからも保存しません。



そして何をすべきか? そして何をすべきか?



私の経験からわかるように、マジック定数は通常、ブロックまたはプログラムモジュールに固有です。 グローバル名前空間をそれらで詰まらせることは十分にまれなので、誰もあなたが書くことを禁じることはありません:



Myclass.h



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





Myclass.cpp



 constexpr float MyClass::m_pi;
      
      





これにより、定数の可読性と可視性および禁止された伝播の問題が完全に解決されること。 このリンクでは、はい、質問は開いたままですが、これは何よりも多くのことです(特に標準の実装を考慮)。 盗作の非難を避けるために、 ここにリンクを追加します。ここでも同様のことが説明されています。



ただし、上記は非常に小さな問題の深刻なループであるように思われませんか? 現実には、誰もが理解しています:




All Articles