SFINAE:删除具有相同原型的函数

时间:2018-05-20 23:41:44

标签: c++ c++14 c++17 sfinae template-function

我想知道这段代码之间的区别是什么:

#include <type_traits>
#include <iostream>

template<typename T> using is_ref = std::enable_if_t<std::is_reference_v<T>, bool>;
template<typename T> using is_not_ref = std::enable_if_t<!std::is_reference_v<T>, bool>;

template<typename T, is_ref<T> = true>
void foo(T&&) {
    std::cout << "ref" << std::endl;
}

template<typename T, is_not_ref<T> = true>
void foo(T&&) {
    std::cout << "not ref" << std::endl;
}

int main() {
    int a = 0;
    foo(a);
    foo(5);
}

并且这个不起作用:

#include <type_traits>
#include <iostream>

template<typename T> using is_ref = std::enable_if_t<std::is_reference_v<T>, bool>;
template<typename T> using is_not_ref = std::enable_if_t<!std::is_reference_v<T>, bool>;

template<typename T, typename = is_ref<T>>
void foo(T&&) {
    std::cout << "ref" << std::endl;
}

template<typename T, typename = is_not_ref<T>>
void foo(T&&) {
    std::cout << "not ref" << std::endl;
}

int main() {
    int a = 0;
    foo(a);
    foo(5);
}

typename = is_ref<T>is_ref<T> = true之间的真正区别是什么?

1 个答案:

答案 0 :(得分:11)

如果删除默认模板参数,则会清楚区别的是什么。函数声明在只是的默认值中不能有所不同。这是不正确的:

void foo(int i = 4);
void foo(int i = 5);

同样,这是不合理的:

template <typename T=int> void foo();
template <typename T=double> void foo();

考虑到这一点,你的第一个案例:

template<typename T, is_ref<T>>
void foo(T&&);

template<typename T, is_not_ref<T>>
void foo(T&&);

这里的两个声明是唯一的,因为第二个模板参数在两个声明之间不同。第一个具有非类型模板参数,其类型为std::enable_if_t<std::is_reference_v<T>, bool>,第二个具有类型为std::enable_if_t<!std::is_reference_v<T>, bool>的非类型模板参数。那些是不同的类型。

然而,你的第二个案例:

template<typename T, typename>
void foo(T&&);

template<typename T, typename>
void foo(T&&)

这显然是相同的签名 - 但我们只是复制了它。这是不正确的。