允许单个值的隐式转换

时间:2017-06-13 01:29:01

标签: 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;
};

我想仅允许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

这可能吗?允许隐式转换0,同时禁止其他值?

1 个答案:

答案 0 :(得分:6)

一种方法:

添加一个带void*

的构造函数

由于文字0可隐式转换为void*空指针,而文字1不是,因此这将指示所需的行为。为安全起见,您可以断言指针在ctor中为空。

缺点是现在你的类可以从任何可隐式转换为void *的东西构建。一些意想不到的事情是如此可转换 - 例如在C ++ 11之前,std::stringstream可以转换为void*,基本上是一个黑客,因为explicit operator bool尚不存在。

但是,只要你意识到潜在的陷阱,这在你的项目中可能会很好。

编辑:

实际上,我记得一种让这更安全的方法。而不是void*使用指向私有类型的指针。

可能看起来像这样:

class Flags {
private:
  struct dummy {};
public:
  Flags (dummy* d) { ... }
  ...
};

文字0转换仍然有效,而且某些用户定义的类型无意中意外转换为Flags::dummy *会更加困难。