我看到了boost实现的一个不错的技巧,他们以某种方式使用()运算符的重载来将boost::system::error_code类的实例求值为bool值
class error_code
{
...
typedef void (*unspecified_bool_type)();
static void unspecified_bool_true() {}
operator unspecified_bool_type() const // true if error
{
return m_val == 0 ? 0 : unspecified_bool_true;
}
...
}
这样就有可能检查类似的错误
...
boost::system::error_code err
some_boost_func(err);
if(err)
{
//handle error
}
....
所以我一直在问自己。。那里发生了什么事?这似乎在某种程度上与函数指针的使用有关。。。如果我调用err
,这会对函数本身或函数指针求值,会发生什么?但是void (*unspecified_bool_type)();
函数如何在中返回值
return m_val == 0 ? 0 : unspecified_bool_true;
它实际上与函数指针的核心功能没有什么关系。这是一个技巧,允许为类编写一个"安全"的类似布尔值的转换。
当希望某个类在if
下可用(通常在逻辑上下文中)时,通常会将其转换为bool
。如
class Error {
public:
operator bool() const { /* whatever */ }
};
现在你可以做
Error err;
...
if (err) // automatically intepreted as `if (err.operator bool())`
...
然而,由于bool
类型是C++中的一个整数类型,当有人不小心写了类似的东西时,这可能会导致不希望的结果
int i = err;
或者在算术表达式中使用CCD_ 6并且它安静地编译。
出于这个原因,在许多情况下,人们更喜欢引入到指针类型的转换,而不是像那样转换到bool
class Error {
public:
operator void *() const {
// Return null pointer for `false` and any non-null pointer for `true`
}
};
这更好,因为可以在if
下使用它,但不能在int
下犯以前的错误。即
if (err) // automatically interpreted as `if (err.operator void *() != 0)`
...
将按预期进行编译和工作,因为编译器将自动将err
对象转换为指针类型。
然而,这种转换也将自动应用于指针上下文(除了布尔上下文),这意味着人们仍然可能意外地进行
void *p = err;
或
free(err);
它将悄悄地编译。这也是不可取的。
为了使意外误用此类错误类变得更加困难,最好使用一些更"奇特"的指针类型,比如指向函数的指针。这正是你在引用的代码中看到的。unspecified_bool_type
被用作基于指针的伪布尔类型。为false
返回空值,为true
返回指向伪unspecified_bool_true
函数的指针。函数unspecified_bool_true
从未被调用,也从未打算被调用。它的存在只是为了保留一些唯一的指针值作为true
的返回。
在某些情况下,人们会更进一步,使用更"奇特"的指针类型:指向类成员类型的指针。但对于大多数应用程序来说,指向函数的指针已经足够"奇特"了。