web-dev-qa-db-ja.com

列挙型クラスの変換を手動で定義することは可能ですか?

通常、次の構文を使用してクラスのキャストを定義できます。

class Test {
public:
  explicit operator bool() { return false; }
};

これを行う方法はありますか、enum class

44

いいえ、ちがいます。

実際には、enum classはまったくクラスではありません。 classキーワードが使用されるのは、スコープ外のenumをスコープ付きenumに突然変更すると、コードを再処理するall enumsコードが必要になるためです。したがって、委員会は、新しいスタイルの列挙と古いスタイルの列挙を区別するために、新しいキーワードにclassのタグを付けることを決定しました。これは、キーワードであるため、enumclass C++で。彼らは別のものを選んだかもしれませんが、それはとにかくはるかに意味がありませんでした。

ただし、classキーワードにもかかわらず、それらは通常の列挙型であり、列挙子(およびそれらに割り当てられている可能性のある値)のみが角かっこ内で許可されます。

23
Matthieu M.

いいえ。ただし、constexprメンバーとコンストラクターを使用して、通常のクラス型を列挙型クラスのように機能させることができます。そして、必要なすべての追加メンバー関数を追加できます。


switchでも機能することの証明:

#include <iostream>

struct FakeEnum
{
    int x;

    constexpr FakeEnum(int y = 0) : x(y) {}

    constexpr operator int() const { return x; }

    static const FakeEnum A, B, Z;
};

constexpr const FakeEnum FakeEnum::A{1}, FakeEnum::B{2}, FakeEnum::Z{26};

std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
    int val;
    st >> val;
    fe = FakeEnum{val};
    return st;
}

int main()
{
    std::cout << "Hello, world!\n";
    FakeEnum fe;
    std::cin >> fe;

    switch (fe)
    {
        case FakeEnum::A:
        std::cout << "A\n";
        break;
        case FakeEnum::B:
        std::cout << "B\n";
        break;
        case FakeEnum::Z:
        std::cout << "Z\n";
        break;
    }
}

switchを使用する場合、intとの暗黙的な相互変換が不要であることの証明:

#include <iostream>

/* pseudo-enum compatible with switch and not implicitly convertible to integral type */
struct FakeEnum
{
    enum class Values { A = 1, B = 2, Z = 26 };
    Values x;

    explicit constexpr FakeEnum(int y = 0) : FakeEnum{static_cast<Values>(y)} {}
    constexpr FakeEnum(Values y) : x(y) {}

    constexpr operator Values() const { return x; }
    explicit constexpr operator bool() const { return x == Values::Z; }

    static const FakeEnum A, B, Z;
};

constexpr const FakeEnum FakeEnum::A{Values::A}, FakeEnum::B{Values::B}, FakeEnum::Z{Values::Z};

std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
    int val;
    st >> val;
    fe = FakeEnum(val);
    return st;
}

int main()
{
    std::cout << "Hello, world!\n";
    FakeEnum fe;
    std::cin >> fe;

    switch (fe)
    {
        case FakeEnum::A:
        std::cout << "A\n";
        break;
        case FakeEnum::B:
        std::cout << "B\n";
        break;
        case FakeEnum::Z:
        std::cout << "Z\n";
        break;
    }
    // THIS ERRORS: int z = fe;
}
16
Ben Voigt

C++では非メンバーキャスト演算子を定義できません。また、列挙型のメンバー関数を定義することはできません。したがって、キャスト演算子を実装するのと同じ方法で、列挙型を他の型に変換する無料の関数を実行することをお勧めします。

例えば.

bool TestToBool(enum_e val)
{
    return false;
}

const char *TestToString(enum_e val)
{
    return "false";
}

これらの列挙型をブール値に関連付けるには、2つのファイル.hと.cppに分割する必要があります。ここにそれが役立つかどうかです:

enum.h

///////////////////////////////
// enum.h
#ifdef CPP_FILE
#define ENUMBOOL_ENTRY(A, B)            { (enum_e) A, (bool) B },
struct EnumBool
{
    enum_e  enumVal;
    bool    boolVal;
};
#else
#define ENUMBOOL_ENTRY(A, B)            A,
#endif


#ifdef CPP_FILE
static EnumBool enumBoolTable[] = {
#else
enum enum_e
{
#endif
ENUMBOOL_ENTRY(ItemA, true),
ENUMBOOL_ENTRY(ItemB, false),
...
};

bool EnumToBool(enum_e val);

enum.cpp

///////////////////////////////
// enum.cpp
#define CPP_FILE
#include "enum.h"

bool EnumToBool(enum_e val)
    //implement

私はそれをコンパイルしなかったので、何かエラーがあればそれを簡単にしてください:)。

4
imreal