42

我正在尝试设计一个应用安全 bool idiom的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

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

我怎样才能让它工作?

4

4 回答 4

57

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

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

    Bool(bool value);
};
于 2017-01-16T20:43:22.813 回答
24

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

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

它比其他构造函数更好地匹配实际以外的任何东西bool,因此将防止隐式转换。

于 2017-01-16T20:44:33.087 回答
18

如果您只需要:
只有“true”或“false”且不能隐式转换为 int/char/pointer 的变量,那么我会考虑使用枚举类:

enum class Bool {
    False,
    True,
};
于 2017-01-17T02:12:17.703 回答
15

我正在尝试设计一个应用安全布尔成语的布尔包装结构。

不。

安全布尔成语仅在 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)不可派生性,因为您制作了Boolfinal 和(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; }
};
于 2017-01-17T14:20:22.143 回答