我想根据已经推导出的struct template参数的类型特征来专门化模板结构的成员函数。我想在模板参数签名时使用该函数的一个版本,而在未签名时需要另一个版本的函数。不确定如何解决这个问题。
结构很简单。它代表了一种尺寸 - 这无疑是写了一千次。这是一个我可以用于所有类型的简单版本,我想:
template<class T>
struct Size
{
T cx;
T cy;
// ... a bunch of functions you might expect.
// normalize function -- avoid negative sizes. make sure size is at LEAST 0, 0
void normalize()
{
cx = std::min(cx, 0);
cy = std::min(cy, 0);
}
};
但是当然,对于无符号类型,处理函数毫无意义。我想让它成为那些类型的无操作。
有一秒钟,我想我可能会尝试使用enable_if和返回类型。
typename std::enable_if<std::is_signed<T>::value, Size&>::type
normalize()
{
cx = std::max(cx, 0);
cy = std::max(cy, 0);
return *this;
}
typename std::enable_if<std::is_unsigned<T>::value, Size&>::type
normalize()
{
return *this;
}
但这不起作用,因为(据我理解)因为,在成员函数的点上,模板“T”已经被推导出来并且SFINAE不能被使用。如果我错了,请纠正我。
所以我想我可以用true_type和false_type写这样的重载:
void normalize(std::true_type)
{
// Ensure signed types are at least zero.
cx = std::max(cx, 0);
cy = std::max(cy, 0);
}
void normalize(std::false_type)
{
// do nothing for unsigned types
}
void normalize()
{
// Call overload based on type.
normalize(std::is_signed<T>::type());
}
但那些似乎毫无意义地构建了一个std::integral_constant<bool>
。这冒犯了我的效率感。如果这是一个更复杂的例子,它甚至可能影响性能。
所以我可以类似地编写一个这样的成员模板函数:
template <typename T>
void normalizeT()
{ }
template<>
void normalizeT<std::true_type>()
{
cx = std::max(cx, 0);
cy = std::max(cy, 0);
}
void normalize()
{
normalizeT<std::is_signed<T>::type>();
}
我猜其他方法还有其他方法。但我有点觉得我错过了一些明显的东西。我总是喜欢花时间把这些东西归结为最简单,最清晰,最强大的版本。
我意识到这不是一个非常复杂的“问题”。正如我所说,我已经可以使代码工作但我正在寻找更一般的教训 - 理解并认识到所涉及的“模式”,因为这是我经常遇到的那种情况。
所以考虑到这些目标,有没有办法更清洁或更健壮地写出来?
答案 0 :(得分:0)
不要手动优化(使用模板)。只需让编译器在std::max
上进行优化(注意:您应该使用std::max
来“避免负面大小”)
为了澄清或normalize
实际上更复杂,您可以这样做:
void normalize()
{
if(std::is_signed<T>::value) {
cx = std::max(cx, 0);
cy = std::max(cy, 0);
// ...
}
}
答案 1 :(得分:0)
除非您正在编写嵌入式硬实时系统,否则在早期优化的要点下这是正方形。您应该编写简单易用的代码,即使它看起来不是最佳的。编译器甚至可能足够智能,可以为您优化掉std::max
的调用!如果程序性能可以接受,那么什么都不会丢失:你已经编写了一次代码并且一切都很好。如果性能成为一个问题,那么你应该分析,而不是猜测你应该分析的瓶颈,只有当它表明无符号类型的标准化是你的问题区域(我无法想象任何情况下这是真的)你会考虑专门化它吗?作为一个无操作。