C++中的operator()重载boost::system::error_code技巧

7
我看到一个由boost实现的不错技巧,他们利用()运算符的重载将boost::system::error_code类的实例转换为布尔值进行评估。
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;
1个回答

15

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

当我们想要在逻辑上下文中使用某个类时(通常是在if语句中),我们通常会使其可转换为bool类型,例如:

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

现在你可以这样做

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

然而,由于在C++中bool类型是一种整数类型,这可能会导致不良后果,当有人意外写出以下内容时:

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时不能犯之前的错误。

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

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

但是,在指针上下文中(除了布尔上下文),这种转换也会自动应用,这意味着仍然可能偶然执行以下操作:

void *p = err;
或者
free(err);

为了防止意外误用错误类,使用一些更“奇特”的指针类型(如指向函数的指针)是个好主意。这就是你在引用代码中看到的情况。 unspecified_bool_type 被用作基于指针的伪布尔类型。对于 false,返回 null 值;对于 true,返回指向虚拟函数 unspecified_bool_true 的指针。函数 unspecified_bool_true 从未被调用过,也没有这个意图。它只存在于为了保留某个唯一的指针值以用作 true 返回。在某些情况下,人们会更进一步地使用一个更“奇特”的指针类型:指向类成员的指针类型。不过对于大多数应用程序而言,指向函数的指针已经足够“奇特”了。


谢谢您快速而准确的回答。所以这是一次转换,与函数无关。 - ramdav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接