一个例子通常比长期解释更好.
您可以在Coliru上编译并运行此代码段.
(另一个前例子也可用)
#include <map>
#include <iostream>
struct MyClass
{
enum class …Run Code Online (Sandbox Code Playgroud) 我遇到了以下代码段
if( 0 != ( x ^ 0x1 ) )
encode( x, m );
Run Code Online (Sandbox Code Playgroud)
什么x ^ 0x1意思?这是一些标准技术吗?
如何enum class在C++ 11中输出a的值?在C++ 03中,它是这样的:
#include <iostream>
using namespace std;
enum A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
Run Code Online (Sandbox Code Playgroud)
在c ++ 0x中,此代码无法编译
#include <iostream>
using namespace std;
enum class A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&' …Run Code Online (Sandbox Code Playgroud) 好的,所以我们在C++ 17,对C++中一个非常好的bitflags接口仍然没有一个令人满意的答案.
我们enum将其成员值放入封闭范围,但是隐式转换为它们的基础类型,因此可以用作 - 如果它们是位标志但拒绝重新分配回枚举而不进行转换.
我们已经enum class解决了名称范围问题,因此它们的值必须显式命名MyEnum::MyFlag或者甚至MyClass::MyEnum::MyFlag,但是它们不会隐式转换为它们的基础类型,因此不能在没有无休止地来回转换的情况下用作位标志.
最后,我们有以下的旧位域C:
struct FileFlags {
unsigned ReadOnly : 1;
unsigned Hidden : 1;
...
};
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是没有好的方法可以将自身整体化 - 人们不得不求助于使用memset或者转换地址或类似的方法来覆盖整个值或者一次初始化它或者一次操作多个位.它也无法命名给定标志的值,而不是它的地址 - 因此没有名称代表0x02,而使用枚举时有这样的名称,因此枚举命名组合时很容易标志,例如FileFlags::ReadOnly | FileFlags::Hidden- 对于比特字段来说,根本不是一个很好的方式.
此外,我们仍然有简单constexpr或#define命名位值,然后根本不使用枚举.这有效,但完全将位值与基础位标志类型分离.也许这最终不是最糟糕的方法,特别是如果位标志值constexpr在一个结构中,为它们提供自己的名称范围?
struct FileFlags {
constexpr static uint16_t ReadOnly = 0x01u;
constexpr static uint16_t Hidden = 0x02u;
...
}
Run Code Online (Sandbox Code Playgroud)
因此,就目前而言,我们有很多技术,但没有一种技术可以说是非常可靠
这是一个具有以下有效位标志的类型,它有自己的名称范围,这些位和类型应该可以与标准的按位运算符一起使用,例如| &^〜,它们应该与0之类的整数值相当,并且任何按位运算符的结果应该保持为命名类型,而不是转换为积分
所有这些都说,有很多尝试在C++中试图产生上述实体 -
DEFINE_ENUM_FLAG_OPERATORS(EnumType),然后定义运算符.&^〜以及相关的赋值操作,如| =等.enable_if元编程允许给定的枚举转换为支持缺失运算符的位标志类型,然后再静默返回.我已经看到过reinterpret_cast常用于对枚举类应用增量,我想知道这种用法在标准C++中是否可以接受.
enum class Foo : int8_t
{
Bar1,
Bar2,
Bar3,
Bar4,
First = Bar1,
Last = Bar4
};
for (Foo foo = Foo::First; foo <= Foo::Last; ++reinterpret_cast<int8_t &>(foo))
{
...
}
Run Code Online (Sandbox Code Playgroud)
我知道,如果是普通的类,那么转换为基类的引用是安全的.但由于枚举类不是隐式转换为其底层类型的事件,因此我不确定上述代码是否以及如何保证在所有编译器中都能正常工作.有线索吗?
我考虑过这里介绍的基于C++ 11的枚举bitset .我想出了一些示例程序:
#include <bitset>
#include <type_traits>
#include <limits>
template <typename TENUM>
class FlagSet {
private:
using TUNDER = typename std::underlying_type<TENUM>::type;
std::bitset<std::numeric_limits<TUNDER>::max()> m_flags;
public:
FlagSet() = default;
FlagSet(const FlagSet& other) = default;
};
enum class Test
{
FIRST,
SECOND
};
int main(int argc, char *argv[])
{
FlagSet<Test> testFlags;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序使用clang ++(clang版本3.8.1(标签/ RELEASE_381/final))编译好clang++ -std=c++11 -o main main.cc.但是,如果我g++ -std=c++11 -o main main.cc改为使用g ++(g ++(GCC)6.2.1 20160830),编译器最终会耗尽系统内存.这是g ++的问题还是这个代码不符合标准?
假设我有:
void f(bool option1 = false, bool option2 =false, bool option3 = false)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我想打电话给:
f(option2=true);
Run Code Online (Sandbox Code Playgroud)
这在C++中是否可行?
有没有办法将所有枚举常量纳入范围?我指的不是类型,而是常量本身。
struct Foo {
enum Bar {
A = 1, B = 2, C = 4, D = 8
};
};
int main() {
using E = Foo;
int v = E::A | E::B | E::C | E::D;
// But is it possible to instead do...
using Foo::Bar::*; // (not real C++)
int v = A|B|C|D; // <-- all enum constants are brought into scope
}
Run Code Online (Sandbox Code Playgroud) 当使用Qt时,许多函数采用类似标志Qt :: LeftDockWidgetArea的参数.
即使我查看了Qt源代码,我也无法理解如何实现这种命名行为.它是普通的C++还是Qt特有的?
假设我有一个MyClass类:
class MyClass {
public:
MyClass();
void setFlag(???);
};
Run Code Online (Sandbox Code Playgroud)
我想像这样调用setFlag方法:
MyClass mc;
mc.setFlag(MyClass::flag1 | MyClass::flag2)
Run Code Online (Sandbox Code Playgroud)
flag1和flag2应该只是0x01和0x02,这是枚举吗?我必须在哪里声明?这个方法的论点是什么?
如果这很明显,我很抱歉,但我不明白.
解决方案(来自答案)
很好.从阅读下面的答案我添加了这个:(请注意,我没有真正需要标志,只是来自枚举的数字,这简化了很多)
namespace MyNames {
typedef enum {
FA = 0,
FB = 1
} Field;
}
class MyClass
{
public:
MyClass();
char getField(MyNames::Field f) const;
};
Run Code Online (Sandbox Code Playgroud)
这确实允许以下调用(不是):
mc.getField(MyNames::FA) //OK
mc.getField(1) //not OK
Run Code Online (Sandbox Code Playgroud) A bool在C++中占用1个字节.但是,为什么bool[8]需要8个字节而不是1个字节?一个字节有足够的空间容纳8位.
我使用-Os标志用GCC编译了这个:
#include <iostream>
using namespace std;
class Foo
{
public:
bool m_bool[8];
};
int main ()
{
cout << "Size: " << sizeof(Foo) << " byte(s) " << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它返回"Size:8 byte(s)".
有没有办法优化它?
我有一部分代码包含以下功能:
void Keyboard(int key)
{
switch (key) {
case GLFW_KEY_A: m_controlState |= TDC_LEFT; break;
case GLFW_KEY_D: m_controlState |= TDC_RIGHT; break;
case GLFW_KEY_W: m_controlState |= TDC_UP; break;
case GLFW_KEY_S: m_controlState |= TDC_DOWN; break;
default: Test::Keyboard(key);
}
}
void KeyboardUp( int key)
{
switch (key) {
case GLFW_KEY_A: m_controlState &= ~TDC_LEFT; break;
case GLFW_KEY_D: m_controlState &= ~TDC_RIGHT; break;
case GLFW_KEY_W: m_controlState &= ~TDC_UP; break;
case GLFW_KEY_S: m_controlState &= ~TDC_DOWN; break;
default: Test::Keyboard(key);
}
}
Run Code Online (Sandbox Code Playgroud)
我知道开关盒是什么,但我不明白这些部件的作用。
m_controlState |= TDC_LEFT
m_controlState &= ~TDC_LEFT
Run Code Online (Sandbox Code Playgroud)
m_controlState …