C++安全布尔包装器



我正在尝试设计一个布尔包装器结构,应用安全布尔习惯用法
解决这个问题的经典实现非常琐碎:框架可能是这样的:

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的变量,那么我会考虑使用枚举类:

enum class Bool {
False,
True,
};

我正在尝试应用安全布尔习惯用法设计一个布尔包装结构。

不要。

安全bool习惯用法仅在C++03及更早版本中相关——如果你通过做以下事情来表达你的类型是"truthy":

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成为最终成员,(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; }
};

最新更新