我正在尝试制作一个类型比较函数,为不同类型做一些自定义比较。
#include <type_traits>
template <typename T>
bool typedCompare(const T& lhs, const T& rhs)
{
return lhs == rhs; // default case, use ==
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return (lhs - rhs) < 1e-10;
}
int main()
{
typedCompare(1, 1);
typedCompare(1.0, 1.0);
return 0;
}
这里我有一个double
的特殊版本,它比较了少量的差异(请忽略我没有使用std::abs()
) .我还有一些其他自定义类型需要进行一些特殊比较,但出于某种原因我无法更改它们的 ==
运算符。
此外,我仍然希望有一个使用 ==
运算符的“包罗万象”的函数。我的问题是,当尝试编译此代码片段时,编译器提示 typedCompare(1.0, 1.0)
不明确,它可以选择提供的两个函数之一。
为什么?我该如何解决这个问题?
谢谢。
最佳答案
Why?
简而言之,您错误地使用了 SFINAE,因此当您为 double 调用 typedCompare
时,两个函数模板均有效。
And how could I resolve this issue?
在这种特殊情况下,修复 SFINAE 以使其正常工作:
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return lhs == rhs; // default case, use ==
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
typedCompare(const T& lhs, const T& rhs)
{
return (lhs - rhs) < 1e-10;
}
请注意,就许多类型的定制而言,此解决方案并不是很好。另一种方法是使用标签调度:
struct floating_point_tag {};
// other tags
template <typename T>
bool typedCompare(const T& lhs, const T& rhs, floating_point_tag) {
return (lhs - rhs) < 1e-10;
}
// implementations for other tags
template <typename T>
bool typedCompare(const T& lhs, const T& rhs) {
if (std::is_floating_point<T>::value) {
return typedCompare(lhs, rhs, floating_point_tag{});
}
// other checks here
return lhs == rhs;
}
最后,对于 C++17,您可以使用 if constexpr
:
template <typename T>
bool typedCompare(const T& lhs, const T& rhs) {
if constexpr (std::is_floating_point<T>::value) {
return (lhs - rhs) < 1e-10;
} else { // add other if-else here
return lhs == rhs;
}
}
关于c++ - SFINAE 函数的 "catch-all"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47640587/