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

One*_*Day 4 c++ templates sfinae enable-if c++11

假设我们有一些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);
}
Run Code Online (Sandbox Code Playgroud)

如果我们如上所述,那么我们如何定义它们呢?他们的两个功能签名看起来像:

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

我已经看到了一个返回std::enable_if_t<...>类似的例子:

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

基于返回类型消除歧义.但我不想退货.

And*_*dyG 9

由于默认参数不是函数签名的一部分,因此不要将它们设置为默认值

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);
};
Run Code Online (Sandbox Code Playgroud)

现场演示


编辑:按流行的需求,这是C++ 17中的相同代码:

class foo{
public:
    template <class S>
    void bar(S&& s)
    {
        if constexpr(std::is_integral_v<S>)
            std::cout << "is integral\n";
        else
            std::cout << "NOT integral\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

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

C++ 17演示


Evg*_*Evg 6

使用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)
{
    ... 
}
Run Code Online (Sandbox Code Playgroud)


Bar*_*rry 5

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

template <bool B, typename T=void>
using enable_if_t = typename std::enable_if<B, T>::type;
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

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);
Run Code Online (Sandbox Code Playgroud)

要么:

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>
Run Code Online (Sandbox Code Playgroud)

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