Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ safe bool wrapper

I'm trying to design a bool wrapper struct applying the safe bool idiom.
The classic implementation to solve this is pretty trivial: the skeleton could be something like this:

struct Bool final
{
  Bool() = default;

  Bool(bool value)
    : _value{value}
  {}

  explicit operator bool() const {
    return _value;
  }

private:
  bool _value{false};
};

The part I'm trying to improve is how Bool is constructed.
For example I want to avoid implicit narrowing by design:

Bool b1(45); // yields warnings, but it compiles
Bool b2{3};  // not ok by standard

I tried to hurt myself using templates, but without success.

How could I make it work?

like image 839
Stefano Azzalini Avatar asked Jan 16 '17 20:01

Stefano Azzalini


4 Answers

You can achieve this by explicitly deleting all other constructors.

struct Bool final
{
    template<class T>
    Bool(T) = delete;

    Bool(bool value);
};
like image 197
François Andrieux Avatar answered Nov 03 '22 13:11

François Andrieux


Add, and explicitly delete a template constructor:

template <typename T>
Bool(T) = delete;

It matches anything other than actual bool better than other constructors, and will thus prevent implicit conversion.

like image 36
yuri kilochek Avatar answered Nov 03 '22 12:11

yuri kilochek


If you just need:
A variable that is only "true" or "false" and cannot be implicitly converted to int/char/pointer then I would look at using an enum class:

enum class Bool {
    False,
    True,
};
like image 18
pilkch Avatar answered Nov 03 '22 12:11

pilkch


I'm trying to design a bool wrapper struct applying the safe bool idiom.

Don't.

The safe bool idiom is only relevant in C++03 and earlier - where if you express that your type is "truthy" by doing something like:

struct A {
    operator bool() const;
};

you'd run into all sorts of issues like:

A{} + 4;    // ok?!
A{} < 0;    // ok?!
A{} == B{}; // ok if B also has operator bool??!

So the safe bool idiom was a solution to this accidental implicit conversion problem, using function pointers (of course, function pointers!).

In C++11, we have a way better solution:

struct A {
    explicit operator bool() const;
};

which does exactly what we want. In fact, it was literally designed to solve this problem. And while the safe bool idiom is fairly complicated scaffolding, explicit operator bool is super straightforward to use and just does the Right Thing. You don't need a wrapper for it - it's actually harder to use your wrapper than to write the explicit operator bool directly.

Moreover, your wrapper imposes on the user (a) non-derivability because you made Bool final and (b) an extra bool member, that you have to keep in sync, so it introduces rather than solves problems. Consider how much more work it would be for you to implement:

template <class T>
struct my_unique_ptr : Bool { ... };

vs

template <class T>
struct my_unique_ptr {
    T* ptr;

    explicit operator bool() const { return ptr; }
};
like image 15
Barry Avatar answered Nov 03 '22 12:11

Barry