c ++从double到bool的隐式转换是危险的

时间:2016-03-12 16:13:06

标签: c++ gcc g++

这是我第二次犯错,通过创建bool类型的变量而不是double。例如,考虑

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;
}

我认为编译器应该告诉我这很糟糕,但我的编译器(g ++)没有用-Wall发出一个小警告......并且它会在测试中导致错误。 是否有一些选项让gcc / g ++有警告(例如在第1行,这显然是坏的)?

4 个答案:

答案 0 :(得分:3)

您可以使用统一初始化来获取错误:

bool x{0.0};
  

错误:输入' double'不能缩小到' bool'在初始化列表中[-Wc ++ 11-narrowing]

它也可用于作业:x = {f()};,并返回return {x};

答案 1 :(得分:2)

虽然我没有直接回答(要求编译器警告),但我确实有opaque typedef library包含" inconvertibool"与bool一样工作的类型,但与其他类型如int或double不同。它为您的示例中的案例提供了编译时错误:

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
         ^

当然,这只会在你持续使用这种类型而不是bool的情况下有所帮助,但它并不能完全符合你的情况,因为你说你的意思是“双重”,而不是'布尔'

答案 2 :(得分:1)

Visual C ++编译器警告转换为bool,但有一个愚蠢的性能警告。通常它是一个不受欢迎的警告,但不幸的是,它不能通过简单的演员来沉默。沉默它的几乎成语是使用双重否定, !! ,bang-bang,例如return !!0.0

你的问题恰恰相反,你想要这样的警告或错误,但仍然是bang-bang几乎成语可以成为解决方案的一部分。

如下所示,您只需在需要布尔值的位置编写Bool而不是bool,并使用!!确保清除bool值,否则你得到编译错误。

关于这一点的好处是,您很可能只需在代码中进行全局搜索和替换,将bool替换为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();
}

使用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> _

如果您希望从Bool隐式转换为bool之外的其他类型而不考虑,请简单地将转换运算符设置为选中的模板,例如构造函数和赋值运算符。

答案 3 :(得分:0)

在c ++中,强制编码器自己处理类型,为运行时释放资源。价格跟踪类型,但效益是效率和速度。

这是一个很小的代价,但奖励是能够在更短的时间内完成更多的工作。