在模板中确定临时的大小

Deciding size of temporary in template

本文关键字:      更新时间:2023-10-16

我有一个模板类,需要能够在一个类型的两个实例之间进行插值。 所以我的类调用了一个名为 interpolate 的用户提供的函数,具有以下签名:

template<typename T>
T interpolate(uint32_t distance, const T& from, const T& to);

在这里,distance0运行到0xFFFF

现在,我想为常见类型的T提供合理的实现,例如uint32_t。 所以我写了一个示例实现(忽略它只针对有符号类型实现):

template<typename T>
inline auto interpolate(uint32_t distance, const T& from, const T& to)
    -> std::enable_if_t<std::is_signed<T>::value, T>
{
    return from + ((distance * (to - from)) / 0xFFFF);
}

这对于小于 32 位的类型非常有效,因为距离永远不会大于 16 位的值,并且distance * (to - from)的结果是uint32_t 。 但是 32 位不足以包含 0xFFFF * uint32_t 的结果——在这种情况下,模板需要一个 64 位的临时模板。

有没有一种标准化的方法,我可以选择一种比T"大"的类型来保存临时结果? 显然,这只需要适用于内部类型;用户的类型仍然需要自己的interpolate实现。

首先,正如你所说,你的插值因子只能从0到0xFFFF。您应该有一个反映这一点的类型,以最大程度地减少潜在错误 - 即不要使用uint32_t而是uint16_t。根据经验,您应该避免使用超过您需要的参数。所以一般的签名是:

template<typename T>
T interpolate(uint16_t factor, const T& from, const T& to);

请注意,在执行插值时,结果可能会超出[from; to]范围 - 因此,界面中不需要更大的类型。

现在,你正在用整数插值使你的生活复杂化。我不知道为什么你不想要浮点插值(特别是对于动画框架,我们不再是 1995 年了!

所以,如果你真的想用整数风格来做,那么你需要一个更大的整数来保存它。您可以做的最简单的操作:

template<typename I> struct bigger_integer;
template<> struct bigger_integer<int8_t>   { typedef int16_t type; };
template<> struct bigger_integer<int16_t>  { typedef int32_t type; };
template<> struct bigger_integer<int32_t>  { typedef int64_t type; };
template<> struct bigger_integer<uint8_t>  { typedef uint16_t type; };
template<> struct bigger_integer<uint16_t> { typedef uint32_t type; };
template<> struct bigger_integer<uint32_t> { typedef uint64_t type; };

并且,在函数中,使用以下更大的类型:

using I = std::make_signed_t<typename bigger_integer<T>::type>;

它甚至应该适用于经过微小修改的无符号类型。

我的意见:使用双打。如果在分析会话后发现它们会导致性能问题,则可以尝试优化它们。但老实说,我怀疑情况会是这样。这里的代码更简单:

template<typename T>
T interpolate(uint16_t factor, const T& from, const T& to)
{
    return T(double(from) + double(factor) * (double(to) - double(from)) / double(0xFFFF));
}

活生生的例子在这里。

相关文章:
  • 没有找到相关文章