13

次のような一連のフラグとクラスがあるとします。

/// <summary>Options controlling a search for files.</summary>
enum class FindFilesOptions : unsigned char
{
    LocalSearch = 0,
    RecursiveSearch = 1,
    IncludeDotDirectories = 2
};

class FindFiles : boost::noncopyable
{
    /* omitted */
public:
    FindFiles(std::wstring const& pattern, FindFilesOptions options);
    /* omitted */
}

そして、発信者が複数のオプションを選択できるようにしたい:

FindFiles handle(Append(basicRootPath, L"*"),
    FindFilesOptions::RecursiveSearch | FindFilesOptions::IncludeDotDirectories);

C++11enum classで厳密に型指定された方法でこれをサポートすることは可能ですか? または、型指定されていない列挙型に戻す必要がありますか?

static_cast(呼び出し元が基になる型に戻ったり戻ったりできることは知っていstatic_castますが、呼び出し元にそれをさせたくありません)

4

5 に答える 5

14

enum classビットマップに esを使用することは確かに可能です。残念ながら、そうするのは少し面倒です: 型に必要なビット操作を定義する必要があります。以下は、これがどのように見えるかの例です。enum class必要なオペレーターの定型コードを定義する適切な名前空間に存在できる他のタイプから es を派生させることができれば、それは素晴らしいことです。

#include <iostream>
#include <type_traits>

enum class bitmap: unsigned char
{
    a = 0x01,
    b = 0x02,
    c = 0x04
};

bitmap operator& (bitmap x, bitmap y)
{
    typedef std::underlying_type<bitmap>::type uchar;
    return bitmap(uchar(x) & uchar(y));
}

bitmap operator| (bitmap x, bitmap y)
{
    typedef std::underlying_type<bitmap>::type uchar;
    return bitmap(uchar(x) | uchar(y));
}

bitmap operator^ (bitmap x, bitmap y)
{
    typedef std::underlying_type<bitmap>::type uchar;
    return bitmap(uchar(x) ^ uchar(y));
}

bool test(bitmap x)
{
    return std::underlying_type<bitmap>::type(x);
}

int main()
{
    bitmap v = bitmap::a | bitmap::b;
    if (test(v & bitmap::a)) {
        std::cout << "a ";
    }
    if (test(v & bitmap::b)) {
        std::cout << "b ";
    }
    if (test(v & bitmap::c)) {
        std::cout << "c ";
    }
    std::cout << '\n';
}
于 2013-08-31T23:53:21.997 に答える
4

テンプレートはうまく機能するenum classため、同様の列挙型のセットで機能する演算子のセットを定義できます。重要なのは、特性テンプレートを使用して、各列挙が準拠/サブスクライブするインターフェイスを指定することです。

はじめに:

enum class mood_flag {
    jumpy,
    happy,
    upset,
    count // size of enumeration
};

template<>
struct enum_traits< mood_flag > {
    static constexpr bool bit_index = true;
};

template< typename t >
struct flag_bits : std::bitset< static_cast< int >( t::count ) > {
    flag_bits( t bit ) // implicit
        { this->set( static_cast< int >( bit ) ); }

    // Should be explicit but I'm lazy to type:
    flag_bits( typename flag_bits::bitset set )
        : flag_bits::bitset( set ) {}
};

template< typename e >
typename std::enable_if< enum_traits< e >::bit_index,
    flag_bits< e > >::type
operator | ( flag_bits< e > set, e next )
    { return set | flag_bits< e >( next ); }

template< typename e >
typename std::enable_if< enum_traits< e >::bit_index,
    flag_bits< e > >::type
operator | ( e first, e next )
    { return flag_bits< e >( first ) | next; }

http://ideone.com/kJ271Z

GCC 4.9 は、これをコンパイルするときにいくつかの暗黙のメンバー関数があったと報告したconstexprので、テンプレートもおそらくそうであるはずです。

これにはおそらく、個別のフラグまたはセットto_scalarのいずれかを指定して符号なし整数型を返すフリー関数または何かが必要です。flag_bits

于 2013-09-01T03:08:20.320 に答える
0

問題は、明示的な列挙型ではなく、クラス スコープです。

C++11 では、コンパイル時定数としての enum は、値を操作する必要がある場合 (ビット単位の操作、インクリメントなど)、一連の constexpr と比較して多くの関心を失います。

于 2013-08-31T23:52:12.020 に答える