42

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?

Calimo
  • 7,510
  • 4
  • 39
  • 61
Stefano Azzalini
  • 1,027
  • 12
  • 21
  • 3
    You may also want to look at some prior art regarding safe bool. For example, [this page](http://www.artima.com/cppsource/safebool.html) goes through the process of making a safe bool and explaining some of the pitfalls which one can run into along the way (for example, an `operator bool` comes with some unintended side effects that other cast operators can avoid) – Cort Ammon Jan 16 '17 at 23:23
  • Thank you! I'll definitely take a look at it! – Stefano Azzalini Jan 17 '17 at 05:38

4 Answers4

57

You can achieve this by explicitly deleting all other constructors.

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

    Bool(bool value);
};
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • 1
    where was the declaration of `_value`? did you omit that for brevity? – cat Jan 16 '17 at 23:27
  • @cat I omitted everything but the constructors. – François Andrieux Jan 16 '17 at 23:28
  • 2
    That code will also delete the default constructor (implicitly), right? – simon Jan 17 '17 at 15:35
  • 5
    @gurka See [default constructor](http://en.cppreference.com/w/cpp/language/default_constructor). "If no user-declared constructors of any kind are provided for a class type[...], the compiler will always declare a default constructor as an inline public member of its class.". Simply providing `Bool(bool value)` is enough to delete the default constructor. – François Andrieux Jan 17 '17 at 15:39
  • 1
    So simple, so elegant. – jabujavi Jan 17 '17 at 17:08
  • is _value global? – J3STER Jan 19 '17 at 03:14
  • @Mr.Robot As previous comments indicate, I omitted most of the class for clarity, as it has no bearing on the concept my answer is trying to illustrate. I've edited my answer to remove the body of the constructor in the hopes that it will avoid future confusion. – François Andrieux Jan 19 '17 at 11:45
  • Should the ctor taking one parameter be marked as `explicit`? – Pawel Jan 21 '17 at 20:19
  • @Pawel It could, but this is one case where it might be desirable to omit it. The purpose of OP`s class is to substitute the type `bool` where it could allow undesirable implicit casts. By leaving the constructor implicit (by omitting `explicit`) you can swap a use of `bool` with this `Bool` class transparently, without any other change. For example, if you added explicit, you couldn't use `Bool` as a function parameter where you would have used `bool` without explicitly casting. By omitting it, the change is transparent. – François Andrieux Jan 22 '17 at 00:32
  • You could add a constructor that takes Bool to support your scenario and still block implicit conversions from other non-bool types. – Pawel Jan 22 '17 at 02:46
  • @FrançoisAndrieux, I used just explicit keyword in constructor and deleted the template constructor and the following is valid without any warnings `Bool b1 {true}; Bool b2{b1}; Bool b3{Bool{false}};` Maybe I misunderstood your above comment, but I thought you said this shouldn't work with explicit. – AdvSphere Jan 26 '18 at 18:57
  • @AdvSphere The first two count as explicit construction. You are explicitly saying you want to create an instance of `Bool`. The third case is a copy, which is a distinct constructor. One example where `explicit` would come into play is if a function expected a `Bool` but you gave it a `bool`. It wouldn't work if the constructor was `explicit`. – François Andrieux Jan 26 '18 at 19:06
  • @FrançoisAndrieux, so basically for the purpose of the OP question, I don't see any gains in using the template constructor against just explicit one. As you mentioned above explicit would come into play if a function expected a Bool and you gave it a bool, but that's not the case in the above class. Am I missing something? Thank you for taking the time to responding! – AdvSphere Jan 26 '18 at 19:14
  • 1
    @AdvSphere As you pointed out, `explicit` won't prevent `Bool foo{true};`, neither would it prevent `Bool foo{1};`. This second case is what OP was trying to prevent. By deleting the constructor template, you prevent `Bool foo{1};`, because it would bind to a deleted constructor. – François Andrieux Jan 26 '18 at 19:18
24

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.

yuri kilochek
  • 12,709
  • 2
  • 32
  • 59
  • 5
    "anything other than actual `bool`" -- and `Bool`: this doesn't, and probably shouldn't, disable the compiler-generated copy and move constructors. –  Jan 16 '17 at 21:18
18

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,
};
pilkch
  • 777
  • 7
  • 17
15

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; }
};
Barry
  • 286,269
  • 29
  • 621
  • 977