7

我已经看到了 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;
4

1 回答 1

15

它实际上与函数指针的核心功能几乎没有(或没有)关系。这是一种技巧,它允许人们为类编写一个“安全的”类似布尔值的转换。

当人们希望某个类在(并且通常在逻辑上下文中)可用if时,通常将其转换为bool. 如在

class Error {
public:
  operator bool() const { /* whatever */ }
};

现在你可以做

Error err;
...
if (err) // automatically intepreted as `if (err.operator bool())`
  ...

然而,由于booltype 在 C++ 中是一个整数类型,当有人不小心写了类似的东西时,这可能会导致不良后果

int i = err;

err在算术表达式中使用,它会安静地编译。

出于这个原因,在许多情况下,人们更喜欢引入指针类型的转换,而不是转换为bool,如

class Error {
public:
  operator void *() const { 
    // Return null pointer for `false` and any non-null pointer for `true`
  }
};

这更好,因为可以在 下使用它if,但不能在 . 下犯上一个错误int。IE

 if (err) // automatically interpreted as `if (err.operator void *() != 0)`
   ...

将按预期编译和工作,因为编译器会自动将err对象转换为指针类型。

但是,这种转换也将自动应用于指针上下文(除了布尔上下文),这意味着人们仍然可能不小心这样做

void *p = err;

或者

free(err);

它会悄悄地编译。这也是不可取的。

为了使意外误用此类错误类变得更加困难,最好使用一些更“奇异”的指针类型,例如指向函数的指针。这正是您在引用的代码中看到的。用作基于指针的unspecified_bool_type伪布尔类型。返回空值并返回false指向虚拟unspecified_bool_true函数的指针true。该函数unspecified_bool_true永远不会被调用,也永远不会被调用。它的存在只是为了保留一些唯一的指针值作为true返回值。

在某些情况下,人们会更进一步,使用一种更加“奇异”的指针类型:指向类成员的指针类型。但是对于大多数应用程序来说,指向函数的指针已经足够“异国情调”了。

于 2012-07-11T06:40:17.847 回答