为什么SFINAE在函数重载时报错

Why SFINAE report error in function overloading

下面的代码编译不了,我只是想测试一下SFINAE,为什么编译不了?

#include <type_traits>
template<typename T>
class TestVoid {
    template<std::enable_if_t<std::is_void_v<T>> * = nullptr>
    void func() {
        std::cout << "void\n";
    }

    template<std::enable_if_t<!std::is_void_v<T>> * = nullptr>
    void func() {
        std::cout << "none void\n";
    }
};

int main() {
    TestVoid<void> t;
    return 0;
}

问题是 std::enable_if 的条件不依赖于 func 本身的模板参数。

您可以将代码更改为

template<typename T>
struct TestVoid {
    template<typename X = T, std::enable_if_t<std::is_void_v<X>> * = nullptr>
    void func() {
        std::cout << "void\n";
    }

    template<typename X = T, std::enable_if_t<!std::is_void_v<X>> * = nullptr>
    void func() {
        std::cout << "none void\n";
    }
};

LIVE

实例化 class 模板时,所有成员函数声明都必须有效。在您的情况下,其中之一不会。相反,您可以将 func 委托给另一个函数模板。

live link

template<typename T, std::enable_if_t<std::is_void_v<T>> * = nullptr>
void func() {
    std::cout << "void\n";
}

template<typename T, std::enable_if_t<!std::is_void_v<T>> * = nullptr>
void func() {
    std::cout << "none void\n";
}

template<typename T>
class TestVoid {
  public:
    void func_member() {
        func<T>();
    }
};

或者,如果您想将 func 的实际实现保留为成员函数:

live link

template<typename T>
class TestVoid {
  public:
    void func_member() {
        func<T>();
    }
  private:
    template<typename U, std::enable_if_t<std::is_void_v<U>> * = nullptr>
    void func() {
        std::cout << "void\n";
    }

    template<typename U, std::enable_if_t<!std::is_void_v<U>> * = nullptr>
    void func() {
        std::cout << "none void\n";
    }
};