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++11 以强类型的方式支持这一点enum class,还是我必须恢复为无类型的枚举?

(我知道调用者可以static_cast返回底层类型static_cast,但我不希望调用者必须这样做)

4

5 回答 5

14

当然可以将enum classes 用于位图。不幸的是,这样做有点痛苦:您需要在类型上定义必要的位操作。下面是一个示例。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 回答
1

如何定义以便FindFiles它需要std::initializer_list.FindFilesOptions

void FindFiles(std::wstring const& pattern, std::initializer_list<FindFilesOptions> options)
{
  auto has_option = [&](FindFilesOptions const option)
  {
    return std::find(std::begin(options), std::end(options), option) != std::end(options);
  };

  if (has_option(FindFilesOptions::LocalSearch))
  {
    // ...
  }

  if (has_option(FindFilesOptions::RecursiveSearch))
  {
    // ...
  }

  if (has_option(FindFilesOptions::IncludeDotDirectories))
  {
    // ...
  }
}

然后你可以这样称呼它:

FindFiles({}, {FindFilesOptions::RecursiveSearch, FindFilesOptions::IncludeDotDirectories});
于 2013-09-01T00:25:23.530 回答
0

如果您不关心性能,请将选项更改为set<FindFilesOptions>!

于 2013-09-01T00:24:15.017 回答
0

问题不在于显式枚举类型,而在于类范围。

使用 C++11,当您需要对值进行操作(按位操作、递增等)时,与一堆 constexpr 相比,枚举作为编译时间常数会引起很多兴趣

于 2013-08-31T23:52:12.020 回答