为什么SFINAE不能与std :: enable_if_t一起使用?

时间:2016-12-28 08:13:05

标签: c++ c++11 templates sfinae template-templates

#include <vector>
#include <list>
#include <iostream>

template
<
    typename T,
    template<typename, typename = std::allocator<T>> class C,
    typename = std::enable_if_t
    <
    std::is_same<std::vector<T>, C<T>>::value
    >
>
void f(const C<T>& coll)
{
    std::cout << "vector" << std::endl;
}

template
<
    typename T,
    template<typename, typename = std::allocator<T>> class C,
    typename = std::enable_if_t
    <
    std::is_same<std::list<T>, C<T>>::value
    >
>
void f(const C<T>& coll)
{
    std::cout << "list" << std::endl;
}

int main()
{
        std::vector<int> c1{ 1, 2, 3 };
        std::list<int> c2{ 1, 2, 3 };       
        f(c1);
        f(c2);
}

Clang 3.8抱怨:

  

错误:模板参数重新定义默认参数:typename = std :: enable_if_t

代码中有什么问题?

2 个答案:

答案 0 :(得分:2)

默认模板参数不参与功能匹配 从编译器的角度来看,当它试图寻找合适的函数时,两者都有以下签名:

Column

因此,template <typename T, template<typename, typename> class C, typename> void f(const C<T>& coll); 的第二个定义实际上是重新定义。

考虑一个最小的例子:

f

编译器如何确定要调用的template<typename = void> void f() {} template<typename = char> void f() {} // ... f<>(); ? 您的代码中或多或少会发生相同的情况。

f移至返回类型,它将按预期工作 在这种情况下,由于错误(如sfinae表达式所预期的那样),替换将排除两个定义中的一个。

答案 1 :(得分:1)

为什么需要SFINAE?一个简单的过载就足够了!

template <typename T>
void f(const std::vector<T>& coll)
{
    std::cout << "vector" << std::endl;
}

template < typename T>
void f(const std::list<T>& coll)
{
    std::cout << "list" << std::endl;
}

int main()
{
    std::vector<int> c1{ 1, 2, 3 };
    std::list<int> c2{ 1, 2, 3 };
    f(c1);
    f(c2);
}

如果您真的想使用SFINAE(在这种情况下毫无意义),您可以使用以下方法修复您的定义:

template
<   
typename T,
         template<typename, typename = std::allocator<T>> class C,
         typename std::enable_if_t
         <
         std::is_same<std::list<T>, C<T>>::value
         >* = nullptr
    >
void f(const C<T>& coll);

为什么你的定义不起作用可以在这里找到: SFINAE working in return type but not as template parameter