我需要 static_cast 我的数字模板值吗?
Do I need to static_cast my numeric template values?
我目前正在编写一个模板化的 C++ 物理库。在我的函数中,我经常必须明确地比较或设置某些数值。我的目标是编写尽可能通用的库,因此我希望尽可能支持浮点和整数类型。
为了获得正确的类型,我经常在我的代码中使用对 T
的显式转换。在我的所有案例中,这当然被解释为 static_cast
。因此,我的问题是:我真的需要 static_cast
这些值吗?或者我可以通过 doing/not 这样做来获得运行时开销吗?
例子:
我目前有这样的功能:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = T(1)) {
return T(0) <= eccentricity < T(1) && T(0) < semi_major_axes;
}
不过,我也可以这样写:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = T(1.0)) {
return T(0.0) <= eccentricity < T(1.0) && T(0.0) < semi_major_axes;
}
像这样:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = 1) {
return 0 <= eccentricity < 1 && 0 < semi_major_axes;
}
或者像这样:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = 1.0) {
return 0.0 <= eccentricity < 1.0 && 0.0 < semi_major_axes;
}
我不太关心这两个版本的可读性。我也不关心在此处使用整数类型可能毫无用处的事实。我只想知道:
- 这些实现之间有区别吗?
- 如果是,那是什么?
- 此外,是否可以根据此代码编译器进行优化?
编辑:
- 如果我想支持自定义数值类型,这会有什么变化吗?
编辑:
正如评论中指出的那样,上面使用的链式比较实际上是错误的。代码应该是这样的:
return T(0) <= eccentricity && eccentricity < T(1) && T(0) < semi_major_axes;
此外,可以使用 constexpr
版本对代码进行运行时优化:
template <class T> constexpr auto is_elliptic(T eccentricity) {
return T(0) <= eccentricity && eccentricity < T(1);
}
template <class T> constexpr auto is_elliptic(T eccentricity, T semi_major_axes) {
return T(0) <= eccentricity && eccentricity < T(1) && T(0) < semi_major_axes;
}
看你想要什么。
此答案假定 T
是 int
或 float
(尽管它适用于 double
、long
或具有类似行为的自定义类型), x
的类型为 T
.
- 如果使用强制转换:
这很容易理解。但是,要注意常量在类型 T
中不可表示的情况。 0.5>x
与 (int)0.5>x
不同。
- 如果不使用转换:
[I]f the promoted operands have different types, additional set of implicit conversions is applied, known as usual arithmetic conversions with the goal to produce the common type [...].
(来自 https://en.cppreference.com/w/cpp/language/operator_arithmetic )
| T | Comparison | Equivalent to |
+-------+------------+---------------+
| int | 0<x | 0<x |
| int | 0.f<x | 0.f<(float)x | (*)
| float | 0<x | (float)0<x |
| float | 0.f<x | 0.f<x |
对于 (*)
,比较是在 float
上进行的,而强制转换常量 (int(0.f<x)
) 将在整数上进行比较。其他情况同理。
关于编译器开销:编译可能稍微慢一些,但考虑到编译标准库头文件的速度已经有多慢,应该没什么大不了的。
我目前正在编写一个模板化的 C++ 物理库。在我的函数中,我经常必须明确地比较或设置某些数值。我的目标是编写尽可能通用的库,因此我希望尽可能支持浮点和整数类型。
为了获得正确的类型,我经常在我的代码中使用对 T
的显式转换。在我的所有案例中,这当然被解释为 static_cast
。因此,我的问题是:我真的需要 static_cast
这些值吗?或者我可以通过 doing/not 这样做来获得运行时开销吗?
例子:
我目前有这样的功能:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = T(1)) {
return T(0) <= eccentricity < T(1) && T(0) < semi_major_axes;
}
不过,我也可以这样写:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = T(1.0)) {
return T(0.0) <= eccentricity < T(1.0) && T(0.0) < semi_major_axes;
}
像这样:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = 1) {
return 0 <= eccentricity < 1 && 0 < semi_major_axes;
}
或者像这样:
template <class T> auto is_elliptic(T eccentricity, T semi_major_axes = 1.0) {
return 0.0 <= eccentricity < 1.0 && 0.0 < semi_major_axes;
}
我不太关心这两个版本的可读性。我也不关心在此处使用整数类型可能毫无用处的事实。我只想知道:
- 这些实现之间有区别吗?
- 如果是,那是什么?
- 此外,是否可以根据此代码编译器进行优化?
编辑:
- 如果我想支持自定义数值类型,这会有什么变化吗?
编辑:
正如评论中指出的那样,上面使用的链式比较实际上是错误的。代码应该是这样的:
return T(0) <= eccentricity && eccentricity < T(1) && T(0) < semi_major_axes;
此外,可以使用 constexpr
版本对代码进行运行时优化:
template <class T> constexpr auto is_elliptic(T eccentricity) {
return T(0) <= eccentricity && eccentricity < T(1);
}
template <class T> constexpr auto is_elliptic(T eccentricity, T semi_major_axes) {
return T(0) <= eccentricity && eccentricity < T(1) && T(0) < semi_major_axes;
}
看你想要什么。
此答案假定 T
是 int
或 float
(尽管它适用于 double
、long
或具有类似行为的自定义类型), x
的类型为 T
.
- 如果使用强制转换:
这很容易理解。但是,要注意常量在类型 T
中不可表示的情况。 0.5>x
与 (int)0.5>x
不同。
- 如果不使用转换:
[I]f the promoted operands have different types, additional set of implicit conversions is applied, known as usual arithmetic conversions with the goal to produce the common type [...].
(来自 https://en.cppreference.com/w/cpp/language/operator_arithmetic )
| T | Comparison | Equivalent to |
+-------+------------+---------------+
| int | 0<x | 0<x |
| int | 0.f<x | 0.f<(float)x | (*)
| float | 0<x | (float)0<x |
| float | 0.f<x | 0.f<x |
对于 (*)
,比较是在 float
上进行的,而强制转换常量 (int(0.f<x)
) 将在整数上进行比较。其他情况同理。
关于编译器开销:编译可能稍微慢一些,但考虑到编译标准库头文件的速度已经有多慢,应该没什么大不了的。