安全布尔成语 - 我找到了更简单的方法,还是我错过了啥?

Posted

技术标签:

【中文标题】安全布尔成语 - 我找到了更简单的方法,还是我错过了啥?【英文标题】:Safe Bool Idiom - did I find a simpler way, or did I miss something?安全布尔成语 - 我找到了更简单的方法,还是我错过了什么? 【发布时间】:2013-09-04 04:31:28 【问题描述】:

我需要找到一个安全的布尔成语解决方案。你知道的,我正在使用 VS 2012、XCode、GCC、LLVM、各种平台,有些支持 C++11 显式转换运算符,有些不支持。我需要一些便携的东西。

我找到了几个,但设计起来似乎很简单,我不得不问,我在这里遗漏了什么吗?

背景(简要):

Web 上的几个示例提供了高度侵入性的方法(基本上将所需的一切都放在给定的类中),或者使用 CRTP 的通用方法,但大多数都基于指向成员函数的指针(其大小和性能难以预测罚款)。

然后我读到了boost::spirit::classicsafe bool,尝试了它,检查了它等等。我喜欢 Spirit 的实现的地方在于它依赖于指向成员数据的指针而不是指向成员函数的指针(使用编译器解决方法'模糊'版本)。

所以我想,指向成员的指针基于什么类型并不重要,实现是有效的,因为除其他外,这些指针指向我们可能使用的对象以外的任何对象的成员.

所以,我尝试了这种事情(我想知道我是否还可以接受)

第一:

class SafeBool 
 private:  SafeBool() : Value( 0 )  
  public:   int Value;
;

SafeBool 承担了boost::spirit 的 safe_bool 模板的工作,而无需承担驱动用户类的负担。

// pointer to member typedef, made widely available

typedef int SafeBool :: *  safe_bool;

//  more about why this define in a moment
#define EXPLICIT_OPERATOR_BOOL operator safe_bool


// here is an example user class, some smart pointer or something 
template< typename T > class SomeSPtr 

 public:  ... other class stuff, obviously

 EXPLICIT_OPERATOR_BOOL() const
       if ( get() ) return &SafeBool::Value; 

        return 0; 
      
;

首先,EXPLICIT_OPERATOR_BOOL 是一个定义,它可以在符合 C++11 的编译器上打开以使用“真正的”显式运算符 bool,而在 VS 2012 和旧 GCC(或者你有什么)上,它可以是就在这里,转换为 operator safe_bool。

人们甚至可以使用相关的定义来返回......比如说

SAFE_BOOL_RETURN( get() )

这可以调整返回逻辑,以使代码在现代和旧编译器之间切换(也就是说,对于 C++11,定义将解析为返回 get() != 0

现在,这在 VS 2012 上与 Spirit 的代码具有相同的基本结果。它允许

SomePtr< AType > p, q; // or some such

if ( p )   // this works as expected

同时拒绝类似代码

if ( p < q ) // compile time error
if ( p > q ) // ""

但它允许这样做:

if ( p == q ) // compiles fine

这与我在许多实现中得到的结果相同,但有几个做了类似的事情:

template< typename T > bool operator ==( const safe_bool & , const T & )
 
  SafeBool CantCompareThatType;
  return false;
 

template< typename T > bool operator ==( const T &, const safe_bool & )
 
  SafeBool CantCompareThatType;
  return false;
 

或类似的诡计,即在使用运算符之前不会实例化的模板代码,并且由于 SafeBool 构造函数是私有的,如果尝试(p == q),则会生成错误。

显然,要排除的所有其他运算符 (!=....) 等将根据需要进行类似处理(响应任何类型的模板函数,其中包含 EXPLICIT_OPERATOR_BOOL 创建函数)。

好的,问题来了。我在这里自欺欺人吗?其他实现强加了从模板类派生并在用户类中放置类似布尔函数的负担 - 或者将整个东西放入用户类中。

在我看来,这种方法使用一个类,SafeBool(它从不用于实例化)来提供指向成员的指针,以及一个类型(类本身),在该类型上可以实现一个安全的 bool 习惯用法,同时在用户的类中只强加一个函数,它本身模仿 C++11 显式转换运算符,可能在需要此习惯用法的地方启用更多向上可移植的代码。

如果我错了,请有人阻止我!

【问题讨论】:

我一直觉得“安全”布尔成语所表达的恐惧被严重夸大了。然而,简单地返回一个指向已声明但从未定义的类型的指针就足够了。我宁愿把时间花在编写有报酬的代码上,也不愿编写解决非问题的代码。 在应用领域,我完全同意你的看法。即使是“私人”的室内图书馆也离不开。另一方面,一个公共分布的图书馆可能会因为不处理它而受到合理的指责。事实上,我开始在内部库中实现这一点,因为它在上个月捕获了我们 3 次,其中一次是两年多的代码。 【参考方案1】:

您的技术有效,并作为http://www.artima.com/cppsource/safebool.html 之一进行了讨论。它讨论了它作为一个有效的选项。它被称为“中毒操作员”,Douglas Gregor 被认为是发明它的人。

我认为真正的 safe_bool 成语通过更加安全而取得了更大的进展。特别是,如果您的 safe_bool 是 int T::* 类型,并且指向 T 的整数成员的唯一指针是私有的,那么只有该类可以生成 safe_bool 的特定变体,因此更容易证明没有人可以生成不安全的模式。由于任何人都可以获取 &SafeBool::Value 的地址,因此它“不太安全”。

病态?也许吧。

【讨论】:

啊,好点子。我将 Value 移至私有,对地址使用了静态成员“get”函数。

以上是关于安全布尔成语 - 我找到了更简单的方法,还是我错过了啥?的主要内容,如果未能解决你的问题,请参考以下文章

服务器怎么导入安全策略的方法和步骤,不管是美国 香港还是站群服务器都一样

“零或零”的最佳红宝石成语

Drupal Ubercart:多币种?

左或右应表示为布尔值还是枚举[关闭]

在 HTTPS 抛出安全警告中找到包含 HTTP 的最简单方法?

LeetCode 1106 解析布尔表达式[栈] HERODING的LeetCode之路