web-dev-qa-db-ja.com

コンパイル時定数を定義する最良の方法

実行時のペナルティがないように、C++ 11で単純な定数値を定義する最良の方法は何ですか?例:(無効なコード)

// Not ideal, no type, easy to put in wrong spot and get weird errors
#define VALUE 123

// Ok, but integers only, and is it int, long, uint64_t or what?
enum {
     Value = 123
};

// Could be perfect, but does the variable take up memory at runtime?
constexpr unsigned int Value = 123;

class MyClass {
    // What about a constant that is only used within a class, so
    // as not to pollute the parent namespace?  Does this take up
    // memory every time the class is instantiated?  Does 'static'
    // change anything?
    constexpr unsigned int Value = 123;

    // What about a non-integer constant?
    constexpr const char* purpose = "example";
    std::string x;
    std::string metadata() { return this->x + (";purpose=" purpose); }
    // Here, the compiled code should only have one string
    // ";purpose=example" in it, and "example" on its own should not
    // be needed.
};

編集

背後に背景がないので、これは役に立たない質問だと言われたので、ここに背景があります。

私はいくつかのフラグを定義しているので、次のようなことができます。

if (value & Opaque) { /* do something */ }

Opaqueの値は実行時に変更されないため、コンパイル時にのみ必要になるため、コンパイルされたコードに含まれるのはばかげているようです。値は、画像内のピクセルごとに複数回実行されるループ内でも使用されるため、速度が低下する実行時ルックアップ(実行時に定数の値を取得するためのメモリアクセスなど)は避けたいと思います。これは 'ではありません。アルゴリズムが現在画像を処理するのに約1秒かかり、私は定期的に100を超える画像を処理するため、最適化が時期尚早であるため、できるだけ高速にしたいと考えています。

これは些細なことで心配しないと言われているので、私は#defineはリテラル値にできるだけ近いので、問題を「考えすぎ」ないようにするための最良のオプションでしょうか。一般的なコンセンサスは、Word Opaqueや使用したい他の定数を誰も使用する必要がないことを望んでいるだけだと思いますか?

14
Malvineous

確かに、これは見た目よりも注意が必要です。

要件を明示的に言い換えるだけです。

  1. 実行時の計算はありません。
  2. 実際の結果を除いて、静的、スタック、またはヒープメモリの割り当てはありません。 (実行可能コードの割り当てを禁止することは不可能ですが、CPUに必要なデータストレージがプライベートであることを確認してください。)

C++では、式は左辺値または前値にすることができます(C++ 11より前およびCでは、右辺値は関連する概念に対応します)。左辺値はオブジェクトを参照するため、代入式の[〜#〜] l [〜#〜]左側に表示される可能性があります。オブジェクトストレージと左辺値は避けたいものです。

必要なのは、prvalueに評価するための識別子またはid-expressionです。

現在、これを実行できるのは列挙子だけですが、ご存知のように、列挙子には何かが必要です。各列挙型宣言は新しい別個の型を導入するため、_enum { Value = 123 };_は整数ではなく、変換する独自の一意の型を導入しますintに。これはピンチで機能しますが、仕事に適したツールではありません。

_#define_を使用できますが、パーサーを完全に回避するため、これはハックです。すべて大文字で名前を付けてから、プログラム内の他の部分に同じすべて大文字の名前が使用されていないことを確認する必要があります。ライブラリインターフェイスの場合、このような保証は特に面倒です。

次善のオプションは関数呼び出しです。

_constexpr int value() { return 123; }
_

ただし、constexpr関数は実行時に評価できるため、注意が必要です。この値を計算として表現するには、もう1つのフープをジャンプする必要があります。

_constexpr int value() {
    /* Computations that do not initialize constexpr variables
       (or otherwise appear in a constant expression context)
       are not guaranteed to happen at compile time, even
       inside a constexpr function. */

    /* It's OK to initialize a local variable because the
       storage is only temporary. There's no more overhead
       here than simply writing the number or using #define. */

    constexpr int ret = 120 + 3;
    return ret;
}
_

現在、定数を名前として参照することはできません。value()である必要があります。関数呼び出し演算子は効率が悪いように見えるかもしれませんが、ストレージのオーバーヘッドを完全に排除する現在の唯一の方法です。

12
Potatoswatter

列挙型の基になる型を指定するC++ 11機能 を検討する必要があると思います。これは、例に適用されます。

enum : unsigned int { Value = 123 };

これにより、列挙型を使用することに対する2つの異論の1つ、つまり、列挙型を表すために実際に使用されるタイプを制御できないことがなくなります。ただし、それでも非整数定数は許可されません。

1
einpoklum

あなたは間違って行くことはできません:

static constexpr const unsigned int Value = 123;

正直なところ、これを気にしないようにしてください。のように、本当に試してみてください。