代码之家  ›  专栏  ›  技术社区  ›  Antoine Morrier

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

  •  6
  • Antoine Morrier  · 技术社区  · 6 年前

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

    #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 回复  |  直到 6 年前
        1
  •  11
  •   Barry    6 年前

    如果您删除默认的模板参数,它将变得清晰的区别是什么。函数声明不能在 只是 他们的违约。这是不正确的:

    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&&)
    

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

    推荐文章