防止在C ++中从float到double的隐式转换

时间:2014-06-29 18:22:37

标签: c++ floating-point implicit-conversion implicit floating-accuracy

基本上,如果我想要这样的话,

double b = sin(2.2);

但是不小心写了这样的东西,

double b = sin(2.2f);

没有错误甚至是警告信息,即使这显然会导致不同的,不准确的,因此不正确的结果。通过强制编译器不执行float到double的任何隐式转换,可以防止这种类型的错误。有没有办法实现这一点,无论是通过编译开关(最好是在Visual Studio中),一些智能宏,还是一个行为类似浮点/双变量并声明自己的运算符的类?

编辑:我也有兴趣使用运算符解决类似问题(例如双b = 2.2f * 2.2f)或赋值(double b = 2.2f)。

4 个答案:

答案 0 :(得分:5)

您可以使用type_assert实用程序。

示例:

#include <cmath>
#include <type_traits>

template<typename T, typename U>
const U& type_assert(const U& u) {
    static_assert(std::is_same<T, U>::value, "...");
    return u;
}

int main() {
    double t = type_assert<double>(std::sin(2.2f));
}

如果预期的类型不同,那么它会给你一个编译器错误。有可能编译器可能会优化它,如果它通过,至少在我的情况下使用-O3

答案 1 :(得分:4)

您可以通过定义类似

的内容来呈现sin(float)不明确的调用
double sin(float x) { abort(); }

然后在sin上调用float会给您一个编译时错误。这是有效的,因为在cmath标题中,std::sin是一个包含float sin(float)double sin(double)long double sin(long double)变体的重载函数。编译器无法知道您是否需要::sin(float)std::sin(float),因此它会引起混乱。

我不一定会建议在您的代码库中留下这类内容,但如果您尝试查找此类错误的所有实例并进行更正,则会非常有用。

答案 2 :(得分:2)

那样的东西?

class MyDouble{
public:
  MyDouble(float _f) {throw "only use double!";}
  MyDouble(double _d) : m_data(_d) {}

  operator float() const {throw "conversion to float occurred!";}
  operator double() const {return m_data;}

private:
  double m_data;
};

但是,是的,你必须在调用数学函数时开始使用这个类,这非常难看:

MyDouble d(3.2);
sin(d);
// or...
cos(MyDouble(2.3));

UPDATE - 运算符实现的一个示例(二元运算符,因为一元必须是类的一部分):

MyDouble operator+(const & MyDouble _lhs, const & MyDouble _rhs){
  MyDouble rez(_lhs);
  rez += _rhs;
  return rez;
}

当然,您不必以这种方式实现(通过使用快捷方式operator+=),但这使代码更易于维护

答案 3 :(得分:1)

我刚刚意识到你正在使用 Microsoft 产品,但我会留下这个答案,因为它可以帮助其他人。

你看过编译器开关了吗?我想有类似的选择。

OMG!我刚刚搜索了Visual Studio选项和警告的帮助! (link

SO 抱歉! 我不知道!这是至少之一我见过的选项和开关列表!更具讽刺意味的是,他们已经开始抓取StackOverflow寻找答案并将其链接回来。

但我确实找到了一些线索:

Compiler Warning (levels 3 and 4) C4244 - 转换'从'type1'转换为'type2',可能会丢失数据

因此使用:

// Enable this to find unintended double to float conversions.
// warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data
#pragma warning(3 : 4244)

GCC / G ++ 切换(

为什么不让编译器告诉你什么时候不小心这样做?

来自g ++ / gcc手册页:

-Wdouble-promotion (C, C++, Objective-C and Objective-C++ only)
  * Give a warning when a value of type "float" is implicitly promoted to "double".
    ... some verbage clipped ...
  * It is easy to accidentally do computations with "double" because floating-point
    literals are implicitly of type "double".

-Wdouble-promotion添加到CXXFLAGS应该会为您提供编译时警告。

还有-fsingle-precision-constant禁止将浮点数隐式转换为双精度数。