允许单个值的隐式转换

Rak*_*rai 5 c++

我有一个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)

我想只允许从FlagFlags类型隐式构造和赋值.但是,我仍然希望一些函数调用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在不允许其他值的情况下进行隐式转换?

Chr*_*eck 6

一种方法:

添加一个构造函数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 *无意中更加困难.