在g ++编译器中,将变窄的转换范围缩小为两倍的怪异警告

问题描述 投票:1回答:3

我具有此功能,用于根据极性表示法创建矢量,其中使用了括号初始化程序:

// 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的不必要的转换?

UPDATE这是最小的可复制示例

#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可以提供帮助。但是主要问题仍然存在(困扰我)-为什么仅在使用初始化初始化时才出现警告?

c++ floating-point double implicit-conversion narrowing
3个回答
1
投票

您没有使用正确的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

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作为输入,而没有任何隐式转换。


0
投票

从您提出的警告来看,您似乎正在使用返回类型为cos()(通常为8个字节)的double,因此,当使用它时,将导致对float(通常为4个字节)进行算术运算)的隐式转换是从floatdouble(较小到较大的类型)。

如果然后将其存储在float中,则存在从较大类型到较小类型的隐式转换,可能会丢失数据,因此出现警告。

由于我们没有您的全部代码,因此很难确定,但这似乎是事实。

#include <iostream>
#include <cmath>

using std::cout, std::endl, std::cos; // (C++17 comma separated)

int main(){
    float x = 2.0;

    cout << sizeof(float) << endl;  // 4
    cout << sizeof(double) << endl << endl; // 8

    auto y = cos(20) * x;  // overloaded --> double cos (double x(conversion)); C++11
    float d = cos(20) * x;  // overloaded --> float cos (float x); C++11

    cout << sizeof(y) << endl;  // 8
    cout << sizeof(d) << endl;  // 4
}

这里一切正常,调用了适当的重载函数,在您看来,这似乎没有发生。

© www.soinside.com 2019 - 2024. All rights reserved.