C++SFINAE enable_if_t成员函数,如何消除歧义?



>假设我们有一些SFINAE成员函数:

class foo{
template <class S, class = std::enable_if_t<std::is_integral<S>::value, S>
void bar(S&& s);
template <class S, class = std::enable_if_t<!std::is_integral<S>::value, S>
void bar(S&& s);
}

如果我们如上所述声明它,那么我们如何定义它们?它们的两个函数签名如下所示:

template <class S, class>
inline void foo::bar(S&& s){ ... do something ... }

我见过返回std::enable_if_t<...>的示例,例如:

template <class S, class>
auto bar(S&& s) -> std::enable_if_t<!std::is_integral<S>::value, S>(...){
... do something ...
}

根据返回类型消除歧义。但我不想归还任何东西。

由于默认参数不是函数签名的一部分,因此请使它们不是默认参数

class foo{
template <class S, typename std::enable_if<std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
template <class S, typename std::enable_if<!std::is_integral<S>::value, int>::type = 0>
void bar(S&& s);
};

现场演示


编辑:根据大众需求,这是C++17中的相同代码:

class foo{
public:
template <class S>
void bar(S&& s)
{
if constexpr(std::is_integral_v<S>)
std::cout << "is integraln";
else
std::cout << "NOT integraln";
}
};

constexpr if 语句对编译器来说是特殊的,因为分支是在编译时选择的,而非 taken 分支甚至没有实例化

C++17 演示

您仍然可以在返回类型中执行此操作。只需保留默认值enable_if(即void(。即使您只是在 C++11 上,只需添加此别名:

template <bool B, typename T=void>
using enable_if_t = typename std::enable_if<B, T>::type;

然后你可以做:

template <class S>
enable_if_t<std::is_integral<S>::value>
bar(S);
template <class S>
enable_if_t<!std::is_integral<S>::value>
bar(S);

或:

template <class S>
auto bar(S) -> enable_if_t<std::is_integral<S>::value>
template <class S>
auto bar(S) -> enable_if_t<!std::is_integral<S>::value>

无论哪种方式,您都有两个正确消除歧义的函数返回void

对于 C++11 编译器,另一种选择是使用标记调度。

template <class S>
void bar(S&& s)
{
bar(std::forward<S>(s), std::is_integral<S>{});
}
template <class S>
void bar(S&& s, std::true_type)
{
... 
}
template <class S>
void bar(S&& s, std::false_type)
{
... 
}

最新更新