5

私のプロジェクトには、列挙メンバーに関連付けられた追加の属性と、列挙型に関連付けられた補助静的メソッドが必要な列挙がたくさんあります。

私の知る限り、これは標準の列挙型クラス MyItem {...} では実現できないため、プロジェクトの列挙型クラスごとに、これらの補助静的メソッドをカプセル化し、補助インスタンスのインスタンス化も行う補助クラス MyItemEnum を用意しています。そのため、追加の属性を取得するためにそれらのメソッドにアクセスできます。

以下に例を示します (可能な限り単純化されていますが、説明するすべての機能はそこにとどまっていると思います)。

MyItem.h

enum class MyItem : unsigned int {
    Item1   = 1,
    Item2   = 5
};

class MyItemEnum {
private:
    MyItem myItem;
    size_t extInfo;

    MyItemEnum(const MyItem& myItem, size_t extInfo);
    ~MyItemEnum();
public:
    static MyItemEnum Item1;
    static MyItemEnum Item2;
    static const MyItemEnum &get(MyItem myItem);

    operator MyItem() const;
    size_t getExt() const;
    bool hasNext() const;
    MyItem next() const;
};

意味は明らかで、ここで .cpp 部分を提供する必要はないと思います... MyItem をインターフェイスで渡される引数として使用し、拡張機能にアクセスする必要がある場合は MyItemEnum を使用します。

私の最初の質問は、上記のアプローチは大丈夫ですか、それともまったく別のものを検討する必要がありますか?

私の 2 番目の質問は、constexpr を使用して実行しようとしているこの列挙の最適化に関するものです。

enum class MyItem : unsigned int {
    Item1   = 1,
    Item2   = 5
};

class MyItemEnum {
private:
    MyItem myItem;
    size_t extInfo;

    constexpr MyItemEnum(const MyItem& myItem, size_t extInfo);
public:
    static MyItemEnum Item1;
    static MyItemEnum Item2;
    static constexpr MyItemEnum &get(MyItem myItem);

    constexpr operator MyItem();
    constexpr size_t getExt();
    constexpr bool hasNext();
    constexpr MyItem next();
};

それはコンパイルされますが、どうやら constexpr を使用する機会がないようです。

MyItemEnum::Item1.getExt()

そのため、コンパイラは Item1 がどの値でインスタンス化されたかを知りません。 リンク時の最適化中に上記の式が constexpr として評価される可能性はありますか? あるいは、私は使用することができます

static constexpr MyItemEnum Item1 = MyItemEnum(MyItem::Item1, 123);

これにより、constexpr コンパイル時の最適化がアクティブになりますが、場合によっては、constexpr をコンパイル時に評価できない場合、コンパイラは MyItemEnum のローカル インスタンスを作成する必要があります(単一のグローバルへの参照を使用する代わりに)。静的インスタンス) これがパフォーマンスの低下につながるのではないかと心配しています (私の実際の列挙型には単一のメンバーよりも多くの属性があるため、ローカルのインスタンス化に時間がかかることがありますか?)。これは正当な懸念ですか?

4

1 に答える 1

0

constexprの使用とその結果のコンパイラ最適化についてはまだ直接経験していませんconstが、クラス自体のメンバーまたはインスタンスを使用するだけで、VS2012 と g++ 4.7 コンパイラの両方でモジュール間の最適化を行うことができます。

class MyItemEnum {
private:
    // make sure to put const here...
    const MyItem myItem;
    const size_t extInfo;

    MyItemEnum(const MyItem& myItem, size_t extInfo);
    ~MyItemEnum();
public:
    // and put const in here too...
    static const MyItemEnum Item1;
    static const MyItemEnum Item2;
};

注意点は、コンストラクターが C++ スタイルの初期化子リスト構文を使用する必要があることです。これは、とにかく定数値を設定するだけであれば問題にはなりません。(初期化リストは、重要なセットアップが必要な場合にのみ面倒になります)。

私は Clang/LLVM でこれを確認していません。そのため、それがツールチェーンである場合は、この単純化された例を使用して、結果を自分でディスアズすることを強くお勧めします。単純なテスト ケースの逆アセンブリは、アセンブリ言語に慣れていなくても簡単に解析できます。この場合、1 つのモジュールにセットされたビルドと 2 つのモジュールに分割されたビルドの 2 つのビルドをコンパイルし、結果を比較して、LTO が必要なジョブを実行していることを確認します。

于 2012-12-30T16:18:11.480 に答える