基于SFINAE的重载冲突

时间:2018-07-18 17:25:51

标签: c++ templates c++14 sfinae enable-if

#include <type_traits>

struct A {};

template <class T, class = std::enable_if_t<std::is_same_v<T, A>>>
void foo(T t) {}

template <class T, class = std::enable_if_t<!std::is_same_v<T, A>>>
void foo(T t) {}

int main()
{
    foo(A{});
    foo(0);
    return 0;
}

我看到foo()的第二个定义的编译错误:

test.cpp:9:6: error: redefinition of ‘template<class T, class> void foo(T)’

之所以这样,是因为SFINAE解析发生在后期。

作为一种解决方法,我可以通过将其更改为第二个foo()来向其添加一个模板参数:

template <class T, class = std::enable_if_t<!std::is_same_v<T, A>>, class = void> void foo(T t) {}

然后错误消失了。但是我想知道还有没有更多惯用的方式来处理这种冲突的过载?对于两个重载,添加一个额外的虚拟模板参数就足够了,但是如果我们有很多这样的重载,那么代码将变得更加混乱,而且乍看之下,这些额外参数的用途一目了然。

1 个答案:

答案 0 :(得分:2)

  

但是我想知道还有更多惯用的方法来处理这种冲突的过载吗?

通过示例

template <class T, std::enable_if_t<std::is_same<T, A>{}> * = nullptr>
void foo(T t) {}

template <class T, std::enable_if_t<!std::is_same<T, A>{}> * = nullptr>
void foo(T t) {}

但是我发现这种方式更加清晰

template <class T>
std::enable_if_t<std::is_same<T, A>{}> foo(T t) {}

template <class T>
std::enable_if_t<!std::is_same<T, A>{}> foo(T t) {}

您还可以添加第二个默认参数。

template <class T>
void foo(T t, std::enable_if_t<std::is_same<T, A>{}> * = nullptr) {}

template <class T>
void foo(T t, std::enable_if_t<!std::is_same<T, A>{}> * = nullptr) {}