C ++ implicit conversion from double to bool is dangerous

This is the second time I make a big mistake by creating a variable of type bool instead of double. For example, consider

double f() { return true; } bool something() { return 0.0; } double g() { bool x = 0.0; // (1) if (something()) { x = f(); // where f() is a function returning a double } return x; } 

I think the compiler should tell me that this is bad, but my compiler (g ++) does not give a small warning with -Wall ... and this leads to an error later in the tests. Is there any option for gcc / g ++ to have warnings (e.g. on line 1, which is clearly bad)?

+5
source share
4 answers

You can use uniform initialization to get an error message:

 bool x{0.0}; 

error: type 'double' cannot be narrowed down to 'bool' in the list of initializers [-WC ++ 11-narrowing]

It can also be used when assigning: x = {f()}; and return return {x}; .

+3
source

Although I don't have a direct answer (a compiler warning was requested), I have an opaque typedef library containing "inconvertibool" that works with bool as well as other types such as int or double. It gives compile-time errors for cases in your example:

 foo.cpp: In function 'double f()': foo.cpp:5:31: error: cannot convert 'inconvertibool {aka opaque::inconvertibool}' to 'double' in return return inconvertibool(true); ^ foo.cpp: In function 'inconvertibool something()': foo.cpp:9:12: error: could not convert '0.0' from 'double' to 'inconvertibool {aka opaque::inconvertibool}' return 0.0; ^ foo.cpp: In function 'double g()': foo.cpp:13:23: error: conversion from 'double' to non-scalar type 'inconvertibool {aka opaque::inconvertibool}' requested inconvertibool x = 0.0; // (1) ^ foo.cpp:15:9: error: no match for 'operator=' (operand types are 'inconvertibool {aka opaque::inconvertibool}' and 'double') x = f(); // where f() is a function returning a double ^ 

Of course, this will only help if you consistently use this type instead of bool, but this does not quite match your scenario, because you said that you meant "double", not "bool".

+2
source

The Visual C ++ compiler warns of conversion to bool , but with a dumb performance warning. This is usually an undesirable warning, but unfortunately it cannot be silenced by a simple work. An almost idiom for silence is to use double negation !! bang-bang e.g. return !!0.0 .

Your problem is the opposite, that you want to receive such a warning or error, but nevertheless an almost-idiom error can be part of the solution.

With the example below, you simply write bool instead of bool where you want to have a boolean, and use !! to ensure clean bool values, otherwise you will get compilation errors.

The best part is that, most likely, you can just do a global search and replace it in your code by 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(); } 

Compilation examples 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 the implicit conversion from bool to any type other than bool to be ignored, just make sure that the conversion operator checks the template, for example, the constructor and assignment operator.

+1
source

In C ++, forcing the encoder to process types on its own, frees resources for runtime. Price tracks types, but the advantage is efficiency and speed.

Its a small price to pay, but reward is the ability to do more in less time.

0
source

Source: https://habr.com/ru/post/1244941/


All Articles