Masked Man
Masked Man

Reputation: 11025

How to prevent implicit conversion from char array to bool

struct Foo {
  void setBar(bool bar_) { bar = bar_; }
  bool bar;
};

int main() {
  Foo f;
  f.setBar("true");
}

The above code compiles successfully due to type conversion, even though a char array is passed where a bool is expected.

Is it possible to cause this code to fail compilation? (C++03 solution preferred, since the compiler at my workplace is ancient.)

I have looked at the following related questions on StackOverflow, but they don't quite address this problem. Preventing implicit conversion in C++, Why does the compiler choose bool over string for implicit typecast of L""?

Upvotes: 11

Views: 5044

Answers (3)

willj
willj

Reputation: 2999

There is a common idiom that both avoids this issue and provides other advantages. Instead of using bool, you can create a custom type that more clearly describes the state that it represents.

The type bool represents only a generic value of true or false, while in actual usage you are overloading these states to mean something more specific. Here's an example using an enum to define a new type:

enum Bar { ok, foobar };

struct Foo {
  void setBar(Bar bar_) { bar = bar_; }
  Bar bar;
};

int main() {
  Foo f;
  f.setBar(foobar); // ok
  f.setBar("true"); // error
}

This still allows implicit conversion from any arithmetic or floating type. To avoid this, you can use C++11's enum class, or roll your own strongly-typed bool like this:

template<class Tag>
struct Bool { bool value; };

typedef Bool<struct BarTag> Bar;
const Bar Ok = { false };
const Bar FooBar = { true };

Upvotes: 7

juanchopanza
juanchopanza

Reputation: 227400

One option would be to make setBar a template, and allow it only to work with bool:

#include <type_traits>

struct Foo 
{
  template <typename T>
  void setBar(T bar_) 
  { 
    static_assert(std::is_same<bool,T>::value, "not bool");
    bar = bar_;         
  }
  bool bar;
};

int main() {
  Foo f;
  f.setBar(true);   // OK
  f.setBar("true"); // Error
  f.setBar(1);      // Error
}

Alternatively, you can use SFINAE with std::enable_if to the same effect, although the compiler warning might be less easy to read:

struct Foo 
{
   template<class T ,
            class = typename std::enable_if<std::is_same<bool,T>::value>::type >
    void setBar(T bar_)
    { 
      bar = bar_;
    } 
  bool bar;
};

Upvotes: 11

jrok
jrok

Reputation: 55395

You can declare a function that takes const char* and don't provide a definition:

void setBar(const char*);

This will make it fail at link time. You're still left will all other implicit conversion, though - from any pointer to bool, integral to bool, floats to bool...

Another option:

struct Foo {
  void setBar(bool bar_) {}
private:
  template<typename T>
  void setBar(T bar) {}
};

This way you'll get an error about it being private if you call it with anything else than bool.

Upvotes: 13

Related Questions