C++安全bool包装器

42

我正在尝试设计一个应用 安全bool习惯用法bool包装器结构体。
经典的解决方案非常简单:框架可能是这样的:

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

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

我该如何使其生效?


3
你可能还想查看一些与安全布尔值相关的现有技术。例如,这个页面介绍了制作安全布尔值的过程,并解释了在此过程中可能遇到的一些陷阱(例如,operator bool会带来一些意想不到的副作用,而其他类型转换运算符可以避免这种情况)。 - Cort Ammon
谢谢!我一定会看看的! - Stefano Azzalini
4个回答

57

您可以通过明确删除所有其他构造函数来实现这一点。

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

    Bool(bool value);
};

1
_value 的声明在哪里?你为了简洁而省略了它吗? - cat
2
那段代码也会删除默认构造函数(隐式地),对吗? - simon
5
请参阅 默认构造函数。如果一个类没有提供任何用户声明的构造函数,编译器会自动声明一个内联公共成员的默认构造函数。仅提供 Bool(bool value) 就足以删除默认构造函数。 - François Andrieux
1
如此简单,如此优雅。 - jabujavi
1
正如@AdvSphere所指出的那样,explicit并不能防止Bool foo{true};,也不能防止Bool foo{1};。后者是OP试图防止的情况。通过删除构造函数模板,您可以防止Bool foo{1};,因为它将绑定到已删除的构造函数。 - François Andrieux
显示剩余9条评论

24

添加并显式删除一个模板构造函数:

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

相比其他构造函数,它更好地匹配除了实际的 bool 之外的任何内容,并因此防止了隐式转换。


5
“anything other than actual bool”意为“除了实际的bool之外的任何东西”,而Bool:这不会且可能不应该禁用编译器生成的复制和移动构造函数。 - user743382

18

如果您只需要一个只能被隐式转换为int/char/pointer的“true”或“false”变量,则我建议使用枚举类:

enum class Bool {
    False,
    True,
};

15

我想设计一个应用安全bool习语的包装结构。

不要这样做。

安全bool习语仅适用于C++03及更早版本 - 在这些版本中,如果您通过执行以下操作之一来表明您的类型是“真实”的:

struct A {
    operator bool() const;
};

如果你不小心遇到以下问题:

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

所以,安全布尔值习惯用法是解决这个意外的隐式转换问题的一种方法,使用函数指针(当然是函数指针!)。

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

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

这正是我们想要的。事实上,它是专门为解决这个问题而设计的。虽然安全布尔技巧是相当复杂的脚手架,但explicit operator bool非常简单易用,而且只做正确的事情。你不需要一个包装器——使用包装器比直接编写explicit operator bool更难。

此外,您的包装器会对用户造成(a)不能派生,因为您将Bool设置为final,以及(b)额外的bool成员,您必须保持同步,所以它引入了问题而不是解决问题。考虑一下要实现多少工作:

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

vs

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接