1

バックグラウンド

私が達成しようとしていること: Java列挙型(つまり、いくつかの追加機能を持つ列挙型)のようなものを実装しようとしています。1 つのクラスが値を表し、もう 1 つのクラスが静的変数を使用して各値を表す可能な値の列挙として機能する、2 つのクラスを使用するソリューションを思いつきました。テンプレートのインスタンス化で列挙型の値を使用する可能性を含め、列挙型の実際の代替品にしたいと考えています。これが機能するには、列挙値が定数式 (constexpr) である必要があります。ただし、constexpr を正しく使用しているかどうかはわかりません。

コード

これが私が思いついたコードです:

class EnumType {
public:
    enum Enum {val_A, val_B, val_C};

    friend class EnumTypeList;

    EnumType()
    : m_ID(val_A), m_foo(0) {}

    constexpr operator Enum() const {return m_ID;};
    constexpr unsigned int getFoo() const {return m_foo;};
protected:
    constexpr EnumType(const Enum v, const int foo)
    : m_ID(v), m_foo(foo) {}
private:
    Enum m_ID;
    int m_foo;
};

class EnumTypeList {
public:
    static constexpr EnumType A = EnumType(EnumType::val_A, 5);
    static constexpr EnumType B = EnumType(EnumType::val_B, 4);
    static constexpr EnumType C = EnumType(EnumType::val_C, 8);
};

このクラスEnumTypeは各値の情報を保持し、いくつかの追加機能を提供します (ここでは、関数を使用してアクセスできる追加の値 m_foo を格納していgetFoo()ます)。列挙自体は、静的な constexpr 変数を含む によって表されEnumTypeListます。ここで、各変数は列挙の可能な値を表します。このコードでは、次のコードのように、テンプレートEnumTypeListで Even の代わりに変数を使用できます。EnumType::Enum.

template <EnumType::Enum T>
class Test {
public:
    void test() {
        std::cout << "Enum is not A" << std::endl;
    }
};

template <>
class Test<EnumType::val_A> {
public:
    void test() {
        std::cout << "Enum is A" << std::endl;
    }
};

int main() {
    Test<EnumTypeList::A> a;
    a.test();

    Test<EnumTypeList::B> b;
    b.test();

    // this shouldn't compile
    /*EnumType x = EnumTypeList::C;
    Test<x> c;
    c.test();*/
}

これは期待どおりに機能します。上記のようにテンプレートのインスタンス化EnumTypeListの代わりに値を使用できますが、それを使用するEnumType::EnumことはできませんEnumType x = EnumTypeList::C;

問題

コードは gcc と clang で警告なしに正しくコンパイルされますが、constexpr を正しく使用しているかどうかはわかりません。問題は、EnumTypeコンストラクターと変換演算子operator Enum()は constexpr ですが、どちらも変数m_IDにアクセスしm_foo、定数ではないということです (代入演算子が必要なため)。

4

1 に答える 1

3

これは問題ありません。リテラル型のメンバーは変更可能です。

定数式で型を使用するには、定数引数を使用して型を構築する必要がありますが、そうしているので問題ありません。

static constexpr EnumType A = EnumType(EnumType::val_A, 5);

constexpr構築されたオブジェクトは有効な定数式であるため、変数の初期化に使用できますA。オブジェクトのメンバーは変更しないので、変更可能かどうかは問題ではありません。

特に Clang は、定数式に関して非常に厳密です。何か間違ったことをすると、エラーが発生します。

このオブジェクトは、定数式が必要な場所で使用できます。

constexpr EnumType A5(EnumType::val_A, 5);

例えば

constexpr int i = A5.getFoo();

このオブジェクトは次のことができません:

EnumType A6(EnumType::val_A, 6);
constexpr int i = A6.getFoo();  // error 
于 2013-06-28T09:21:05.517 に答える