我有一个Flags类似于std::bitset替换旧代码库中的bitpacked整数的类.为了强制遵守较新的类,我想禁止从int类型中隐式转换.
enum class Flag : unsigned int {
none = 0,
A = 1,
B = 2,
C = 4,
//...
};
class Flags {
public:
Flags();
Flags(const Flag& f);
explicit Flags(unsigned int); // don't allow implicit
Flags(const Flags&);
private:
unsigned int value;
};
Run Code Online (Sandbox Code Playgroud)
我想只允许从Flag和Flags类型隐式构造和赋值.但是,我仍然希望一些函数调用Flags接受一个文字0,但不接受其他整数:
void foo(const Flags& f);
foo(Flags(0)); // ok but ugly
foo(1); // illegal because of explicit constructor
foo(0); // illegal, but I want to allow this
Run Code Online (Sandbox Code Playgroud)
这可能吗?允许0在不允许其他值的情况下进行隐式转换?
一种方法:
添加一个构造函数void*.
由于literal 0可以隐式转换为void*空指针,而literal 1不是,因此这将指示所需的行为.为安全起见,您可以断言指针在ctor中为空.
缺点是现在你的类可以从任何可隐式转换为可构造的东西构建void *.一些意想不到的东西是如此可转换 - 例如在C++ 11之前,可以std::stringstream转换为void*,基本上是一个黑客,因为explicit operator bool还没有.
但是,只要您意识到潜在的陷阱,这在您的项目中可能会很好.
编辑:
实际上,我记得一种让这更安全的方法.而不是void*使用指向私有类型的指针.
它可能看起来像这样:
class Flags {
private:
struct dummy {};
public:
Flags (dummy* d) { ... }
...
};
Run Code Online (Sandbox Code Playgroud)
文字0转换仍然有效,并且某些用户定义的类型意外地转换为Flags::dummy *无意中更加困难.