具有模板类成员功能的SFINAE

时间:2018-12-11 04:57:21

标签: c++ c++11 sfinae

我试图了解SFINAE,并在尝试将其应用于模板类成员函数时遇到了一个问题。感谢Why doesn't SFINAE (enable_if) work for member functions of a class template?,我能够设置一个基本示例(Run online):

template<typename T>
class Foo{
    public:
    template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
    void sfinae() { // Foo<anything else>
        std::cout << "sfinae default" << std::endl;
    }

    template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
    void sfinae() { // Foo<int>
        std::cout << "sfinae int" << std::endl;
    }

    template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
    void sfinae() { // Foo<float>
        std::cout << "sfinae float" << std::endl;
    }
};

对此我有两个后续问题:
1. 如何区分成员函数的声明和定义?
我尝试了如下定义:

template <typename T>
template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
    void Foo<T>::sfinae() { // Foo<anything else>
        std::cout << "sfinae default" << std::endl;
    }

但这会导致编译错误。

2.包罗万象的默认情况(打印sfinae-default)当前必须写为not(type1, type2,...),可能非常大。是否可以使用更短或更清洁的解决方案?

修改: 根据@Jans的回答,这里是corrected solution

1 个答案:

答案 0 :(得分:1)

异常定义中,删除默认参数,它们取自声明:

template <class T>
template <typename U, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int>>
void Foo<T>::sfinae() { // Foo<anything else>
    std::cout << "sfinae default" << std::endl;
}

其他都一样

  

包罗万象的默认情况(打印sfinae-default)当前必须写为not(type1, type2,...),可能非常大。是否可以使用更短或更清洁的解决方案?

为此,您需要添加一个额外的参数来对重载进行排序,从而使所有对象的排名最低,这通常是由于省略号参数并不比其他任何参数类型都好:

template <typename U = T>
void sfinae(...);

template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
void sfinae(int);

template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
void sfinae(int);

Foo<char>{}.sfinae(0); // select the catch-all

这意味着,由于...比任何其他参数都要糟糕(int...更好),因此仅在其他两个参数被考虑时才考虑重载sfinae(...)无法调用,即是否为SFINAE。