Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ operator() overload boost::system::error_code trick

Tags:

c++

boost

I've seen a nice trick made by an boost Implementation, they somehow use the overloading of the () operator to evaluate an instance of the class boost::system::error_code to an bool value

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;
}
...
}

This results in the possibility to check for an error like this

...
boost::system::error_code err

some_boost_func(err);
if(err)
{
    //handle error
}
....

So i keep asking myself.. what happend there? This seems to somehow relate to the use of function pointers... What happens if i call err does this evaluate the function itself or the function pointer? But how can a void (*unspecified_bool_type)(); function return a value in

return m_val == 0 ? 0 : unspecified_bool_true;
like image 800
ramdav Avatar asked Jul 11 '12 06:07

ramdav


1 Answers

It really has little (or nothing) to do with core functionality of function pointers specifically. It is a trick that allows one to write a "safe" boolean-like conversion for the class.

When one wants some class to be usable under if (and generally in logic contexts), one typically makes it convertible to bool. As in

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

and now you can do

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

However, since bool type is an integral type in C++, this might lead to undesirable consequences, when someone accidentally writes something like

int i = err;

or uses err in an arithmetic expression and it quietly compiles.

For this reason, in many cases people prefer to introduce a conversion to pointer type, instead of conversion to bool, as in

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

This is better since one can use it under if, but one can't make the previous mistake with int. I.e.

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

will compile and work as intended, since the compiler will automatically convert err object to pointer type.

However, such conversion will be automatically applied in pointer contexts as well (in addition to boolean contexts), meaning that one can still accidentally do

void *p = err;

or

free(err);

and it will quietly compile. This is also undesirable.

To make it more difficult to accidentally misuse such error class, it is a good idea to use some more "exotic" pointer type, like pointer to a function. This is exactly what you see in the code you quoted. The unspecified_bool_type is used as a pointer-based pseudo-boolean type. Null value is returned for false and pointer to a dummy unspecified_bool_true function is returned for true. The function unspecified_bool_true is never called and never intended to be called. It only exists to reserve some unique pointer value to be used as true return.

In some cases people take it one step further and use an even more "exotic" pointer type: pointer-to-class-member type. But for most applications pointer to function is "exotic" enough.

like image 70
AnT Avatar answered Nov 12 '22 04:11

AnT