【问题标题】:Weird narrowing conversion double to float warnings in g++ compilerg ++编译器中奇怪的缩小转换双浮点警告
【发布时间】:2020-02-07 08:52:46
【问题描述】:

我有这个函数用于从极坐标符号中创建一个向量,其中使用了大括号初始化器:

// Constructs a 2D vector from XY-coordinates.
inline vector2(float x, float y) : x_(x), y_(y) { }

// Constructs a 2D vector from polar coordinates
static vector2 polar(float r, float phi) {
    return {r * cos(phi), r * sin(phi)};
}

在 MSVS 中一切似乎都很好,但 g++ 编译器显示的警告对我来说似乎很奇怪:

vector2.h:37:23: warning: narrowing conversion of ‘(((double)r) * cos(((double)phi)))’ from ‘double’ to ‘float’ inside { } [-Wnarrowing]
             return {r * cos(phi), r * sin(phi)};
                     ~~^~~~~~~~~~

如果我使用构造函数警告消失:

// Constructs a 2D vector from polar coordinates
static vector2 polar(float r, float phi) {
    return vector2(r * cos(phi), r * sin(phi));
}

为什么会出现此警告?这是否意味着编译后的程序会从floatdouble 并返回到float 进行不必要的转换?

更新 这是最小的可重现示例

#include <iostream>
#include <cmath>

using std::cout;
using std::endl;

class Pair {
public:
    float x_;
    float y_;

    inline Pair(float x, float y) : x_(x), y_(y) {};

};

Pair braced(float a) {
    return {a * 2, cos(a) * 3};
}

Pair constr(float a) {
    return Pair(a * 2, cos(a) * 3);
}

Pair stdbraced(float a) {
    return {a * 2, std::cos(a) * 3};
}

Pair stdconstr(float a) {
    return Pair(a * 2, std::cos(a) * 3);
}

int main() {
    float x = 2.0;
    auto a = braced(x);
    cout << a.x_ << ' ' << a.y_ << endl;
    auto b = constr(x);
    cout << b.x_ << ' ' << b.y_ << endl;
    auto c = stdbraced(x);
    cout << c.x_ << ' ' << c.y_ << endl;
    auto d = stdconstr(x);
    cout << d.x_ << ' ' << d.y_ << endl;
}

g++ test.cpp -o test的输出:

test.cpp: In function ‘Pair braced(float)’:
test.cpp:15:27: warning: narrowing conversion of ‘(cos(((double)a)) * (double)3)’ from ‘double’ to ‘float’ inside { } [-Wnarrowing]
         return {a*2,cos(a)*3};
                     ~~~~~~^~

所以使用std::cos 会有所帮助。但主要问题仍然存在(并且困扰我) - 为什么警告仅在使用支撑初始化时出现?

【问题讨论】:

  • vector2 似乎是一个构造函数。类是如何定义的?您应该提供一个最小的 Reproducible 示例。

标签: c++ floating-point double implicit-conversion narrowing


【解决方案1】:

如果您能发布整个源代码,将会很有帮助。

根据您发布的内容,我假设您没有类似的东西

using namespace std;

所以cos()sin() 是旧的C 版本。他们都期望double 类型的输入。 cosf()sinf() 是期望浮点数的函数。由于您使用的是 c++,因此您希望使用 STL 函数而不是旧的 C 函数。

所以请执行以下操作

static vector2 polar(float r, float phi) {
    return {r * std::cos(phi), r * std::sin(phi)};
}

STL 函数是重载的,因此它们将 float 和 double 作为输入,没有任何隐式转换。

【讨论】:

    【解决方案2】:

    您没有使用正确的cossin

    #include <cmath>
    
    class vector2 {
    public:
    float x_, y_;
    // Constructs a 2D vector from XY-coordinates.
    inline vector2(float x, float y) : x_(x), y_(y) { }
    };
    
    // Constructs a 2D vector from polar coordinates
    static vector2 polar(float r, float phi) {
        return {r * std::cos(phi), r * std::sin(phi)};
    }
    

    使用std::cosstd::sin 会得到正确的结果,因为它们像this 一样重载:

    double cos (double x);
    float cos (float x);
    long double cos (long double x);
    double cos (T x);           // additional overloads for integral types
    

    编辑: 在compiler explorer 中运行它只是给出相同的警告,但按下cppinsights 按钮会给出更正确的错误:

    /home/insights/insights.cpp:17:20:错误:在初始化列表 [-Wc++11-narrowing] 中,非常量表达式不能从类型“double”缩小到“float” 返回 {a * 2, cos(a) * 3}; ^~~~~~~~~~ /home/insights/insights.cpp:17:20:注意:插入显式强制转换以消除此问题 返回 {a * 2, cos(a) * 3}; ^~~~~~~~~~

    这导致了initializer list 的定义,其中提到了list-initialize 和“缩小”小节

    缩小转化范围 列表初始化通过禁止以下内容来限制允许的隐式转换:

    • 从浮点类型转换为整数类型
    • 从 long double 转换为 double 或 float 以及从 double 转换为 float,除非源是常量表达式且不会发生溢出
    • 从整数类型转换为浮点类型,除非源是一个常量表达式,其值可以完全存储在目标类型中
    • 从整数或无作用域枚举类型转换为不能表示原始所有值的整数类型,除非源是一个常量表达式,其值可以完全存储在目标类型中

    所以,如果我没看错,那应该是一个错误。

    【讨论】:

    • @gazand 编辑了更好的诊断。
    猜你喜欢
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多