C++ safe bool习惯用法是否可以在不必派生自safe_bool类的情况下实现?

C++ safe bool习惯用法是否可以在不必派生自safe_bool类的情况下实现?,c++,operators,boolean,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; 这几乎没问题,只

有没有一个技巧可以让安全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;
这几乎没问题,只是a==b仍将编译,因为可以比较成员指针。与上面相同的实现,但使用指向成员函数的指针而不是指向成员变量的指针,则存在完全相同的问题

已知的能够完美工作的实现(例如,如所述,或者boost中使用的safe_bool)要求可测试类派生自提供实际操作符实现的类

事实上,我认为没有办法解决这个问题,但我不能完全确定。我尝试了一些看起来有点费劲的东西,但我认为它可能会工作,但它根本没有编译。为什么不允许编译器看到运算符返回一个安全的东西,而这个东西又可以转换为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

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

无需任何特殊基类即可轻松实现:

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行简单代码就可以将其输入。

为什么不允许编译器查看

我对安全布尔没有答案,但我能做到这一点。这是因为一个转换序列最多可以包含一个用户定义的转换(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
应该编译,而不是链接

我不确定是否
==
=是否所有需要重载的运算符,但是,是否可以使用指向数据成员的指针执行其他操作?这可能会变得臃肿。事实上,这并不比巴特的回答好多少,我之所以提到这一点,是因为你的第一次尝试已经接近成功。

这应该是可行的:

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)
情况,这取决于两种类型都转换为不兼容的指针类型。。。对于两个布尔值来说非常有意义。您想要一个安全的布尔值还是绑定、阻塞和链接的布尔值?;-)对布尔值有意义,是的,但对两个完全不相关的类没有意义!出于兴趣,如果执行第一个版本,然后将
MyTestableClass::operator==
设为私有,会发生什么?这有什么问题吗?它不应该阻止
a==b
进行任何转换吗?实际上,从
safe\u bool
的helper继承通常是一件好事,所以我并不奇怪所有标准实现都是这样做的。。如果使用operator==(constmytestableclass&),它不会做任何不正常的事情。如果使用bool操作符==(const bool_type&),那么它确实给出了我想要的行为。这样写有点奇怪,但它确实有用。也许你可以把它作为一个答案来发布?我不认为这有什么“当然”,我已经编辑了我的答案:-)是的,这个解决方案基本上就是我所说的“与上面相同的实现,但是使用指向成员函数的指针而不是指向成员变量的指针”…哈!这个确实有效。它的缺点是不能完全重复使用,但我想这就是你在不派生时得到的。这里进行继承的主要原因是对实现的重用。对于a==b,修改确实是可以的,但如果b是另一个也具有运算符bool_类型的类型,则不可以;最后一个正是我想要避免的。。如果MyTestableClass和MyOtherTestableClass都将运算符==(const bool_type&)声明为私有,则此操作有效。
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); }
};