Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent implicit conversion from char array to bool

Tags:

c++

casting

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""?

like image 455
Masked Man Avatar asked Aug 27 '13 11:08

Masked Man


3 Answers

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.

like image 139
jrok Avatar answered Oct 12 '22 17:10

jrok


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;
};
like image 31
juanchopanza Avatar answered Oct 12 '22 19:10

juanchopanza


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 };
like image 38
willj Avatar answered Oct 12 '22 19:10

willj