我有这个函数,用于从极坐标符号创建一个向量,其中使用大括号初始值设定项:
// 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));
}
为什么会出现此警告?这是否意味着编译的程序将进行从float
到double
并返回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
确实有帮助。但主要问题仍然存在(并困扰我(- 为什么仅在使用支撑初始化时才出现警告?
如果您发布整个源代码,那将很有帮助。
从您发布的内容来看,我假设您没有类似的东西
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 函数是重载,因此它们将浮点数和双精度作为输入,没有任何隐式转换。
您没有使用正确的cos
和sin
#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::cos
和std::sin
给出正确的结果,因为它们是像这样的重载:
double cos (double x);
float cos (float x);
long double cos (long double x);
double cos (T x); // additional overloads for integral types
编辑: 在编译器资源管理器中运行它 只需给出相同的警告,但按 cppinsights 按钮会给出更正确的错误:
/home/insights/insights.cpp:17:20:错误:无法在初始值设定项列表中将非常量表达式从类型"double"缩小到"float" [-Wc++11-narrowing] 返回 {a * 2, cos(a( * 3}; ^~~~~~~~~~/home/insights/insights.cpp:17:20:注意:插入显式强制转换以消除此问题 返回 {a * 2, cos(a( * 3}; ^~~~~~~~~~
然后导致初始化程序列表的定义,其中提到了列表初始化和"缩小"小节
缩小转化范围 列表初始化通过禁止以下内容来限制允许的隐式转换:
- 从浮点类型转换为整数类型 从长双精度转换为双精度或浮点数,
- 以及从双精度到浮点数的转换,除非源是常量表达式并且不会发生溢出
- 从整数类型转换为浮点类型,除非源是常量表达式,其值可以精确存储在目标类型中
- 从整数或无作用域枚举类型转换为不能表示原始值的所有值的整数类型,除非 source 是常量表达式,其值可以精确存储在目标类型中
因此,如果我没看错的话,那应该是一个错误。