我有一个模板类,需要能够在两个类型的实例之间进行插值。所以我的类调用一个名为interpolate
的用户提供的函数,具有以下签名:
template<typename T>
T interpolate(uint32_t distance, const T& from, const T& to);
此处,distance
从0
到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位&#39;值得,distance * (to - from)
的结果是uint32_t
。但是32位不足以包含0xFFFF * uint32_t
的结果 - 在这种情况下,模板需要64位临时值。
我是否有一种标准化的方式可以选择a&#34;尺寸更大&#34;比T
保留临时结果?显然,这只需要适用于内在类型;用户&#39;类型仍然需要自己的interpolate
实现。
答案 0 :(得分:1)
首先,正如您所说,您的插值因子只能从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));
}