C++ 安全布尔包装器

C++ safe bool wrapper

我正在尝试设计一个应用 safe bool idiom.
bool wrapper 结构 解决这个问题的经典实现非常简单:骨架可能是这样的:

struct Bool final
{
  Bool() = default;

  Bool(bool value)
    : _value{value}
  {}

  explicit operator bool() const {
    return _value;
  }

private:
  bool _value{false};
};

我要改进的部分是 Bool 的构造方式。
例如,我想通过设计避免隐式缩小:

Bool b1(45); // yields warnings, but it compiles
Bool b2{3};  // not ok by standard

我试图用模板伤害自己,但没有成功。

我怎样才能让它发挥作用?

您可以通过显式删除所有其他构造函数来实现此目的。

struct Bool final
{
    template<class T>
    Bool(T) = delete;

    Bool(bool value);
};

添加和显式删除模板构造函数:

template <typename T>
Bool(T) = delete;

它与实际 bool 以外的任何其他构造函数相匹配,因此可以防止隐式转换。

如果你刚好需要:
一个只有 "true" 或 "false" 并且不能隐式转换为 int/char/pointer 的变量然后我会考虑使用枚举 class:

enum class Bool {
    False,
    True,
};

I'm trying to design a bool wrapper struct applying the safe bool idiom.

不要。

safe bool 惯用语仅在 C++03 及更早版本中相关 - 如果您通过执行以下操作来表达您的类型是 "truthy":

struct A {
    operator bool() const;
};

你会 运行 遇到各种问题,例如:

A{} + 4;    // ok?!
A{} < 0;    // ok?!
A{} == B{}; // ok if B also has operator bool??!

所以 safe bool 习语是解决这个意外隐式转换问题的方法,它使用函数指针(当然是函数指针!)。

在 C++11 中,我们有一个更好的解决方案:

struct A {
    explicit operator bool() const;
};

完全我们想要的。其实就是literally designed来解决这个问题。虽然 safe bool 习语是相当复杂的脚手架,但 explicit operator bool 使用起来超级简单,而且做正确的事。您不需要包装器 - 使用包装器实际上比直接编写 explicit operator bool 更难。

此外,您的包装器强加给用户 (a) non-derivability 因为您将 Bool 设为最终版本和 (b) 一个额外的 bool 成员,您必须保持同步,所以它引入而不是解决问题。考虑一下您需要执行多少工作:

template <class T>
struct my_unique_ptr : Bool { ... };

template <class T>
struct my_unique_ptr {
    T* ptr;

    explicit operator bool() const { return ptr; }
};