如何使用is_class SFINAE?

时间:2018-09-20 13:29:51

标签: c++ sfinae

我正在尝试学习SFINAE。但是,我看到的所有例子都太复杂了,而取得的成就却微不足道。我发现的最有意义的SFINAE是这个:

template<typename T>
class is_class {
    typedef char yes[1];
    typedef char no [2];

    template<typename C>
    static yes& test(int C::*); // selected if C is a class type

    template<typename C>
    static no&  test(...);      // selected otherwise

public:
    static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};

但是,所有文档都专注于编写没有任何main功能的模板。因此,我不知道如何在main函数中使用它们,该函数在编译时不会失败。

PS。让我们忘记std::is_class(如果有任何巨魔评论)。

2 个答案:

答案 0 :(得分:2)

您可以这样使用它:

template <typename T>
std::enable_if_t<is_class<T>::value>
foo(const T&)
{
    std::cout << "is a class\n";
}

template <typename T>
std::enable_if_t<!is_class<T>::value>
foo(const T&)
{
    std::cout << "is not a class\n";
}

,然后在main中:

int main()
{
    std::string s;
    int i = 42;

    foo(s); // a class
    foo(i); // not a class
}

在函数上使用SFINAE的常规方法是:

  • template <typename T, std::enable_if_t<some_trait<T>::value, int> = 0>
    void foo(const T&);
    
  • template <typename T>
    std::enable_if_t<some_trait<T>::value> foo(const T&);
    
  • template <typename T>
    void foo(const T&, std::enable_if_t<some_trait<T>::value, int> = 0);
    

您也可以将SFINAE与“表达式”一起使用

 template <typename T>
 auto foo(const T& t) -> decltype (bar(t)); // Only available if `bar(t)` exists.

答案 1 :(得分:0)

想象一下,您有一个(相当无用的)函数,以字节为单位返回传递的参数的大小,但是您希望该函数仅可用于类(出于某些不同的奇怪原因)。 SFINAE类的用法:

template<typename T>
class is_class {
    typedef char yes[1];
    typedef char no [2];

    template<typename C>
    static yes& test(int C::*); // selected if C is a class type

    template<typename C>
    static no&  test(...);      // selected otherwise

public:
    static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};

可以是:

template <typename T, typename = std::enable_if_t<is_class<T>::value>>
auto get_class_size(T t) {
    return sizeof(T);
};

然后在main()中:

int main() {
    std::vector<int> some_vec;
    int some_int;

    std::cout << get_class_size(some_vec) << '\n';
    //std::cout << get_class_size(some_int) << '\n'; // will result in
    // compilation error
}