可以实现安全的bool成语,而不必从safe_bool类派生?

时间:2010-10-15 09:15:35

标签: c++ operators boolean

有没有一个技巧可以让安全bool成语完全正常工作,而不必从实际实现的类中派生出来?

对于'完全正常工作',我的意思是该类有一个运算符允许它被测试,好像它是一个布尔值,但是以安全的方式:

MyTestableClass a;
MyOtherTestableClass b;
  //this has to work
if( a );
if( b );
  //this must not compile
if( a == b );
if( a < b );
int i = a;
i += b;

使用此实现时的示例

struct safe_bool_thing
{
  int b;
};
typedef int safe_bool_thing::* bool_type;
safe_bool( const bool b ) { return b ? &safe_bool_thing::b : 0; }

class MyTestableClass
{
  operator bool_type () const { return safe_bool( someCondition ); }
}

它几乎没问题,除了== b仍然会编译,因为可以比较成员指针。与上面相同的实现,但是指向成员函数而不是指向成员变量的指针具有完全相同的问题。

完美运行的已知实现(例如,如here所述,或boost中使用的safe_bool)要求可测试类派生自提供实际运算符实现的类。

我实际上认为没有办法绕过它,但我不完全确定。我尝试了看起来有点fischy的东西,但我认为它可能有用,但根本不编译。为什么编译器不允许看到运算符返回safe_bool_thing,而safe_bool_thing又可以转换为bool()并因此被测试?

struct safe_bool_thing
{
  explicit safe_bool_thing( const bool bVal ) : b( bVal ) {}
  operator bool () const { return b; }
private:
  const bool b;
  safe_bool_thing& operator = ( const safe_bool_thing& );
  bool operator == ( const safe_bool_thing& );
  bool operator != ( const safe_bool_thing& );
};

class MyTestableClass
{
  operator safe_bool_thing () const { return safe_bool_thing( someCondition ); }
};

MyTestableClass a;
if( a ); //conditional expression of type 'MyTestableClass' is illegal

3 个答案:

答案 0 :(得分:2)

这应该有效:

class MyTestableClass
{
private:
  void non_comparable_type() {}
public:
  typedef void (MyTestableClass::* bool_type)();

  operator bool_type () const { return (someCondition ? &MyTestableClass::non_comparable_type : 0); }
};

class MyOtherTestableClass
{
private:
  void non_comparable_type() {}
public:
  typedef void (MyOtherTestableClass::* bool_type)();

  operator bool_type () const { return (someCondition ? &MyOtherTestableClass::non_comparable_type : 0); }
};

对于阻塞if (a == b)的情况,它取决于这两种类型转换为不兼容的指针类型的事实。

答案 1 :(得分:1)

“为什么编译器不允许看到”

我没有安全布尔的答案,但我能做到这一点。这是因为转换序列最多可包含1个用户定义的转换(13.3.3.1.2)。

至于的原因 - 我认为有人认为如果他们可以进行任意多次用户定义的转换,就很难找出隐式转换。它带来的困难是你不能用转换来编写一个“行为类似于内置类型”的类。如果你编写一个用于惯用“一次”用户定义转换的类,那么该类的用户就不会“花费”。

并不是说你可以完全匹配内置类型的转换行为,因为通常无法指定转换的等级以匹配您正在模仿的类型的转换等级。

编辑:稍微修改您的第一个版本:

#define someCondition true

struct safe_bool_thing
{
    int b;
};
typedef int safe_bool_thing::* bool_type;
bool_type safe_bool( const bool b ) { return b ? &safe_bool_thing::b : 0; }

class MyTestableClass
{
public:
    operator bool_type () const { return safe_bool( someCondition ); }
private:
    bool operator==(const MyTestableClass &rhs);
    bool operator!=(const MyTestableClass &rhs);
};

int main() {
    MyTestableClass a;
    MyTestableClass b;
    a == b;
}

a == b将无法编译,因为函数重载解析会忽略可访问性。只有选择了正确的功能后才能测试辅助功能。在这种情况下,正确的函数是MyTestableClass::operator==(const MyTestableClass &),这是私有的。

在课堂内,a == b应该编译但不能链接。

我不确定==!=是否是您需要重载的所有运算符,但是,对于指向数据成员的指针,还有什么可以做的吗?这可能会变得臃肿。这并不比巴特的回答更好,我只是提到它,因为你的第一次尝试接近工作。

答案 2 :(得分:0)

编辑:哦!我没有正确地阅读您的要求,因此以下内容并不能满足所有要求。

没有任何特殊的基类很容易:

struct MyClass
{
   int some_function () const;

   typedef int (MyClass:: * unspec_bool_type) () const;
   operator unspec_bool_type () const
   {
       return some_condition ? &MyClass::some_function : 0;
   }
};

因此,给定成员函数的合适成员变量,只需5行简单代码即可实现。