我正在尝试创建一个函数 X,它在提供成员函数 Y 时专门化,如果未提供成员函数 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。
知道如何解决这个问题吗?
注意:这不同于仅仅检测类是否具有给定签名的函数。对不起,如果这个问题似乎是这样问的!下面接受的答案应该使我的意图更清楚。
最佳答案
典型的方法是分派(dispatch)到一对函数,如果满足您的条件,其中一个是首选,另一个只是后备。好处是你甚至不需要 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
的转换序列比到 ...
的转换序列要好,所以如果类型有你想要的成员函数,那么重载将是首选,即使两者都是可行的候选人。
关于c++ - 具有函数和模拟部分模板特化的 SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40196724/