【问题标题】:c++ implicit conversion from double to bool is dangerousc++ 从 double 到 bool 的隐式转换是危险的
【发布时间】:2016-06-27 20:54:22
【问题描述】:

这是我第二次犯大错,创建了一个 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 行,这显然很糟糕)?

【问题讨论】:

标签: c++ gcc g++


【解决方案1】:

你可以使用统一初始化来报错:

bool x{0.0};

错误:在初始化列表 [-Wc++11-narrowing] 中,类型 'double' 不能缩小为 'bool'

它也可以用于赋值:x = {f()};,并返回return {x};

【讨论】:

【解决方案2】:

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

这是一个很小的代价,但回报是能够在更短的时间内做更多的事情。

【讨论】:

  • “强制编码器自己处理类型,为运行时释放资源”。 C++ 是静态类型的,即在编译时检查所有类型,因此对于运行时类型没有什么可释放的。
【解决方案3】:

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

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

使用下面举例说明的想法,您只需在需要布尔值的地方写 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:在函数'Bool something()'中: foo.cpp:43:22:错误:无法将 '0.0' 从 'double' 转换为 'Bool' { 返回 TO_BOOL 0.0; } // ΓåÉ Line 43 ^ foo.cpp:在函数'double g()'中: foo.cpp:48:25:错误:请求从“双”转换为非标量类型“布尔” 布尔 x = TO_BOOL 0.0; // ΓåÉ Line 48 ^ foo.cpp:50:13: 错误:'operator=' 不匹配(操作数类型为'Bool' 和'double') x = TO_BOOL f(); // 其中 f() 是一个返回双精度的函数 ^ foo.cpp:23:14: 注意: 候选: 模板 Bool& Bool::operator=(T) 自动运算符=( T const 其他 ) ^ foo.cpp:23:14:注意:模板参数扣除/替换失败: foo.cpp:12:11: 注意: 候选: Bool& Bool::operator=(const Bool&) 布尔类 ^ foo.cpp:12:11:注意:没有已知的参数 1 从 'double' 到 'const Bool&' 的转换 foo.cpp:12:11: 注意: 候选: Bool& Bool::operator=(Bool&&) foo.cpp:12:11:注意:参数 1 从 'double' 到 'Bool&&' 的已知转换 foo.cpp:在函数'int main()'中: foo.cpp:58:18:警告:建议在 '||' 内的 '&&' 周围加上括号[-括号] 返回 a && b ||某物(); ^ c:\my\forums\so\105> g++ foo.cpp -D CLEAN foo.cpp:在函数'int main()'中: foo.cpp:58:18:警告:建议在 '||' 内的 '&&' 周围加上括号[-括号] 返回 a && b ||某物(); ^ c:\my\forums\so\105> g++ foo.cpp -D CLEAN -Wno-括号 c:\我的\论坛\so\105> _

如果您希望不考虑从 Boolbool 以外的其他类型的隐式转换,只需将该转换运算符也设为检查模板,如构造函数和赋值运算符。

【讨论】:

  • 除了“性能”方面,您对可读性有何看法?即使这显然不是 VC 警告的意图,我也经常看到它指出可以通过显式检查变得更清晰的代码。例如,double x = 0.0; bool b = (x != 0.0);double x = 0.0; bool b = x;
【解决方案4】:

虽然我没有直接的答案(要求编译器警告),但我确实有一个 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 时才会有所帮助,但它与您的场景不太匹配,因为您说您的意思是 'double',而不是 'bool'。

【讨论】:

    猜你喜欢
    • 2017-04-10
    • 1970-01-01
    • 2016-11-26
    • 2010-12-12
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    相关资源
    最近更新 更多