The Visual C++ compiler warns about the conversion to bool
, but with a silly performance warning. Usually it's an undesired warning, but unfortunately it can't be silenced with a simple cast. The almost-idiom for silencing it is to use a double negation, !!
, bang-bang, e.g. return !!0.0
.
Your problem is the opposite, that you want such a warning or error, but still the bang-bang almost-idiom can be part of a solution.
With the idea exemplified below, you simply write Bool
instead of bool
where you want a boolean, and use the !!
to ensure clean bool
values, or else you get compilation errors.
The nice thing about this is that most probably you can just do a global search and replace in your code, replacing bool
with Bool
.
#ifdef CLEAN
# define TO_BOOL !!
#else
# define TO_BOOL
#endif
#define STATIC_ASSERT( e ) static_assert( e, #e )
#include <type_traits> // std::is_same
#include <utility> // std::enable_if_t
class Bool
{
private:
bool value_;
public:
operator bool() const { return value_; }
template< class T
, class Enabled_ = std::enable_if_t<std::is_same<T,bool>::value, void>
>
auto operator=( T const other )
-> Bool&
{ value_ = other; return *this; }
Bool(): value_() {}
template< class T
, class Enabled_ = std::enable_if_t<std::is_same<T,bool>::value, void>
>
Bool( T const value )
: value_( value )
{}
};
auto f()
-> double
{ return 0.0; }
auto something()
-> Bool
{ return TO_BOOL 0.0; } // ← Line 43
auto g()
-> double
{
Bool x = TO_BOOL 0.0; // ← Line 48
if (something()) {
x = TO_BOOL f(); // where f() is a function returning a double
}
return x;
}
auto main() -> int
{
Bool a, b, c;
return a && b || something();
}
Example compilations with g++:
c:\my\forums\so\105> g++ foo.cpp
foo.cpp: In function 'Bool something()':
foo.cpp:43:22: error: could not convert '0.0' from 'double' to 'Bool'
{ return TO_BOOL 0.0; } // ← Line 43
^
foo.cpp: In function 'double g()':
foo.cpp:48:25: error: conversion from 'double' to non-scalar type 'Bool' requested
Bool x = TO_BOOL 0.0; // ← Line 48
^
foo.cpp:50:13: error: no match for 'operator=' (operand types are 'Bool' and 'double')
x = TO_BOOL f(); // where f() is a function returning a double
^
foo.cpp:23:14: note: candidate: template<class T, class Enabled_> Bool& Bool::operator=(T)
auto operator=( T const other )
^
foo.cpp:23:14: note: template argument deduction/substitution failed:
foo.cpp:12:11: note: candidate: Bool& Bool::operator=(const Bool&)
class Bool
^
foo.cpp:12:11: note: no known conversion for argument 1 from 'double' to 'const Bool&'
foo.cpp:12:11: note: candidate: Bool& Bool::operator=(Bool&&)
foo.cpp:12:11: note: no known conversion for argument 1 from 'double' to 'Bool&&'
foo.cpp: In function 'int main()':
foo.cpp:58:18: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
return a && b || something();
^
c:\my\forums\so\105> g++ foo.cpp -D CLEAN
foo.cpp: In function 'int main()':
foo.cpp:58:18: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
return a && b || something();
^
c:\my\forums\so\105> g++ foo.cpp -D CLEAN -Wno-parentheses
c:\my\forums\so\105> _
If you want implicit conversion from Bool
to some other type than bool
to not be considered, simply make also that conversion operator a checked template, like the constructor and assignment operator.