SFINAE具有功能和模拟部分模板专业化

时间:2016-10-22 20:27:16

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

我正在尝试创建一个在提供成员函数Y时专门化的函数X,并且如果未提供成员函数Y,则函数X使用全局非成员函数Y来实现相同的效果。

我目前正尝试使用以下代码实现此目的

template <typename Container, typename std::enable_if_t<std::is_same<
            decltype(std::declval<Container>().y()),
            decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
    return std::forward<Container>().y();
}

template <typename Container, typename std::enable_if_t<!std::is_same<
            decltype(std::declval<Container>().y()),
            decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
    return y(std::forward<Container>(container);
}

但是当容器同时具有成员函数y和全局非成员函数时,y也适用于它。存在编译错误,因为对于函数的第二个版本,模板参数生成错误,因为需要成员函数y。

我知道如何解决这个问题吗?

注意:这与仅检测某个类是否具有给定签名的功能不同。对不起,如果问题似乎要求!下面接受的答案应该让我的意图更清楚。

1 个答案:

答案 0 :(得分:3)

典型的方法是调度到一对函数,其中如果满足条件则优先选择一个函数,而另一个函数只是后备函数。好消息是你甚至不需要enable_if,只需要跟踪decltype

template <class C>
auto do_something_impl(C&& c, int)
    -> decltype(std::forward<C>(c).y())
{
    return std::forward<C>(c).y();
}

template <class C>
auto do_something_impl(C&& c, ...)
    -> decltype(y(std::forward<C>(c))
{
    return y(std::forward<C>(c));
}

现在只需传入0

template <class C>
auto do_something(C&& c)
    -> decltype(do_something_impl(std::forward<C>(c), 0))
{
    return do_something_impl(std::forward<C>(c), 0);
}

int的转换序列优于...的转换序列,因此如果类型具有您想要的成员函数,则即使两者都是可行的候选者,也会优先选择该重载。