有没有一个技巧可以让安全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
答案 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行简单代码即可实现。