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""?
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
.
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;
};
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 };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With