如何使用枚举类作为一组标志
How does one use an enum class as a set of flags?
假设我有一组标志和一个类似的类:
/// <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
返回,但我不希望调用者必须这样做)
位图当然可以使用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';
}
模板与enum class
配合良好,因此您可以定义在类似枚举类型的集合上工作的运算符集。关键是使用traits模板来指定每个枚举符合/订阅的接口
首先:
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
集。
如何定义FindFiles
,使其取FindFilesOptions
的std::initializer_list
。
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});
问题不在于显式枚举类型,而在于类作用域。
使用C++11,当您需要对值进行操作(按位操作、递增等)时,与一堆constexpr相比,枚举作为编译时常数会引起很多兴趣。
如果您不关心性能,请将选项更改为set<FindFilesOptions>
!
相关文章:
- 在 c++ 中拥有一组结构的正确方法是什么?
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 程序以使用 C++ 中的 while 循环查找一组数字的最小值
- 一组值的零开销下标运算符
- 使用一组结构,避免在一组结构中出现重复的结构
- CMake:我们可以为一组不形成可执行文件或库的特定文件指定包含目录吗?
- 合并一组模板专用化
- 如何更好地检查两个 char 变量是否在一组值中?
- C++有没有办法强制重写一组方法,如果其中一个方法在子类中具有重写?
- 给定一个枢轴点,按照它们与枢轴点构成的角度递增顺序对一组点进行排序
- 如何从一组变量中查找最低值
- 如何根据对的第二个元素对 STL c++ 中的一组对进行排序?
- 如何通过查找迭代器结果分配给一组对的元素
- 读取一组用户输入,按升序排序,然后打印结果
- 如何从一组具有从左到右优先级的整数值创建有序整数键?
- 在 c++ 中定义一组 set 的迭代器
- 使用 C++20 概念强制类实现一组方法
- 这是定义一组递归规则的正确方法吗?
- 什么是建议的一组编译器标志,以帮助减少错误
- 如何使用枚举类作为一组标志