c++ - SFINAE 函数的 "catch-all"?

标签 c++ c++11 templates sfinae

我正在尝试制作一个类型比较函数,为不同类型做一些自定义比较。

 #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/

相关文章:

c++ - 有没有摆脱 'invalid conversion int* to int' C++的解决方案?

c++ - 如何在 execvp() 的实现中替换 alloca?

c++ - 有没有一种方法可以自动将 .natvis 附加到使用 -DebugExe 启动的调试 session ?

c++ - 部分特化可变参数模板类的方法

c++ - 从范围类型获取迭代器类型

c++ - 自下而上的模板 MergeSort 迭代

c++ - 重载模板化类二元运算符*

C++将具有重载构造函数的对象添加到另一个对象

C++:结构访问速度比基本变量慢?

c++ - C++11 中的泛型函数指针