C++ C++;保险箱包装

C++ C++;保险箱包装,c++,boolean,safe-bool-idiom,C++,Boolean,Safe Bool Idiom,我正在尝试应用安全bool习惯用法设计bool包装结构。 解决这个问题的经典实现非常简单:框架可以是这样的: struct Bool final { Bool() = default; Bool(bool value) : _value{value} {} explicit operator bool() const { return _value; } private: bool _value{false}; }; 我试图改进的部分是如何构造Bo

我正在尝试应用安全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
我试图用模板伤害自己,但没有成功


如何使其工作?

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

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

    Bool(bool value);
};
struct Bool final
{
模板
Bool(T)=删除;
Bool(Bool值);
};

添加并明确删除模板构造函数:

template <typename T>
Bool(T) = delete;
模板
Bool(T)=删除;

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

如果您只需要:
一个仅为“true”或“false”且不能隐式转换为int/char/pointer的变量,然后我将使用枚举类:

enum class Bool {
    False,
    True,
};
我正在尝试应用安全bool习惯用法设计bool包装结构

不要

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??!
这正是我们想要的。其实就是为了解决这个问题。虽然safebool的习惯用法相当复杂,但显式操作符bool的使用非常简单,而且做的事情是正确的。你不需要一个包装器——实际上使用包装器比直接编写
显式操作符bool
更难

此外,您的包装器对用户施加了(a)不可派生性,因为您使
Bool
成为final;(b)额外的
Bool
成员,您必须保持同步,因此它引入而不是解决问题。考虑一下要实现多少工作:

template <class T>
struct my_unique_ptr : Bool { ... };
模板
结构my_unique_ptr:Bool{…};
vs

模板
结构我的唯一性{
T*ptr;
显式运算符bool()常量{return ptr;}
};

“除实际
bool
”之外的任何内容——和
bool
:这不会,也可能不应该禁用编译器生成的复制和移动构造函数。您可能还想了解一些有关安全bool的现有技术。例如,通过制作一个安全bool的过程,并解释在制作过程中可能遇到的一些陷阱(例如,
操作员bool
会带来一些其他演员操作员可以避免的意外副作用),谢谢!我一定要看一看!
\u值的声明在哪里?为了简洁起见,您是否省略了它?该代码还将删除默认构造函数(隐式),对吗?@gurka-See。“如果没有为类类型[…]提供任何类型的用户声明构造函数,编译器将始终将默认构造函数声明为其类的内联公共成员。”。只需提供
Bool(Bool值)
就足以删除默认构造函数。如此简单,如此优雅。@AdvSphere正如您所指出的,
explicit
不会阻止
Bool foo{true},它也不会阻止
boolfoo{1}。第二个案例是OP试图阻止的。通过删除构造函数模板,可以防止
boolfoo{1},因为它将绑定到已删除的构造函数。
template <class T>
struct my_unique_ptr : Bool { ... };
template <class T>
struct my_unique_ptr {
    T* ptr;

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