【发布时间】:2013-08-19 11:30:24
【问题描述】:
在模板参数包中确定常见数字类型的最佳方法是:
- 最小尺寸,
- 不损失精度,并且
- 将参数包中的任何类型转换为这种“理想”的通用类型时,不会有上溢/下溢的风险吗?
可变参数模板 (best_common_numeric_type) 可以这样使用:
template<typename... NumericTypes>
auto some_numeric_func(const NumericTypes&...)
-> typename best_common_numeric_type<NumericTypes...>::type;
并具有如下实例化:
[1] best_common_numeric_type<long, unsigned long, float, double, int>::type = double
[2] best_common_numeric_type<unsigned int, unsigned long>::type = unsigned long
[3] best_common_numeric_type<signed int, signed long>::type = signed long
[4] best_common_numeric_type<signed int, unsigned int>::type = signed long
[5] best_common_numeric_type<signed int, unsigned long>::type = int128_t (maybe)
因此,例如 [4],::type 必须是 signed long,因为 signed int 不能保存 unsigned int 而不存在溢出风险,反之,unsigned int 不能保存 @987654331 @ 没有下溢的风险。
这同样适用于 [5],但现在 signed long 已不再足够,因为它无法容纳 unsigned long 而没有溢出的风险。
(实现可能是 data model 特定的,但你明白了。)
那么在 C++11 中实现这一目标的最佳方法是什么?
【问题讨论】:
-
std::common_type 有什么问题?
-
@DanielKO:我对所有 5 个案例都尝试了
std::common_type,它适用于 1-3,因为它们是非常简单的案例,但是对于案例 [4],“返回”unsigned int(而不是signed long) 和unsigned long用于案例 [5](而不是比long更宽的有符号整数类型)。这是因为这些类型可以转换为无符号对应,但并非没有潜在的下溢,best_common_numeric_type必须避免这种下溢。 -
<signed long long, unsigned long long>怎么样?有些组合没有结果。还有<long long, double>。 (还要注意long在某些系统上是 32 位的,所以 #4 可能是错误的) -
@MooningDuck:正确。在这些情况下,模板只能推断出可能的“最佳”类型(并且可能会生成警告或 static_assert 失败,这些细节可以为了回答这个问题而被忽略)。对于您的第二点,我在问题中指出,实现可能是“数据模型”特定的,但也可以忽略(即可以假设数据模型)。与数据模型无关的解决方案可能是使用
signed_int_with_size_gt<...>::type等模板,但这超出了本问题的范围。 -
@MikeTusar:如果你可以解决两个问题,那么扩展它来解决任何数字都是微不足道的。
标签: c++ templates c++11 variadic-templates template-meta-programming