如何使用这个is_class SFINAE?

How to use this is_class 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(以防任何巨魔评论)。

假设您有一个(相当无用的)函数,该函数 returns 传递的参数的大小(以字节为单位),但您希望该函数仅可用于 classes(对于某些不同的,奇怪的原因)。你的 SFINAE 的使用 class:

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
}

你可能会这样使用它:

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
}

Demo

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

  • 在模板参数中:

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

    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.