enable_if,SFINAE和模板参数?

时间:2020-07-22 02:03:51

标签: c++

我正在尝试了解enable_if和SFINAE。到目前为止,我对模板的使用已明确地将模板参数传递给模板参数或在实例化过程中推导模板参数。我在下面的代码中感到困惑,如何使enable_if <> :: type的成员(typedef int类型)成为模板参数。即参数列表将变为<class T = int, int* = nullptr>。我希望像这样的参数为int Z = nullptr

有人知道我在了解enable_if分配的这些模板参数为何起作用时所缺少的东西吗?

谢谢

 #include <type_traits>
#include <iostream>

#if 1
template <class T,
         typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void do_stuff(T& t) {
    std::cout << "do_stuff integral\n";
}
#endif

#if 0 // understood
template <class T>
typename std::enable_if<std::is_integral<T>::value,
                                 void>::type
do_stuff(T& t) {
    std::cout << "do_stuff integral\n";
}
#endif

struct S {};
int main(int argc, char *argv[])
{
    int i = 1;
    do_stuff(i);
    //do_stuff<S>(S{});
    return 0;
}

2 个答案:

答案 0 :(得分:2)

template parameters有两种:

  • 类型模板参数
  • 非类型模板参数

模板参数的名称是可选的

模板参数可以具有默认值

类型模板参数

已命名,未默认

template <class T>
struct X {};

用法:

X<int> x{};

已命名,默认

template <class T = int>
struct X {};

用法:

X<> x1{};
X<char> x2{};

未命名的非默认

template <class>
struct X {};

用法:

X<int> x{};

未命名,默认值

template <class = int>
struct X {};

用法:

X<> x1{};
X<char> x2{};

非类型模板参数

已命名,未默认

template <int I>
struct X {};

用法:

X<24> x{};

已命名,默认

template <int I = 24>
struct X {};

用法:

X<> x1{};
X<11> x2{};

未命名,未默认

template <int>
struct X {};

用法:

X<11> x{};

未命名,默认值

template <int = 24>
struct X {};

用法:

X<> x1{};
X<11> x2{};

对于SFINAE,该技术需要默认值。由于您不在乎类中的参数,因此可以跳过其名称。至于类型还是非类型,您可以选择在特定情况下更容易编写的类型。

答案 1 :(得分:1)

该参数是匿名的。类型和默认值已指定,但是以后没有实际引用的内容。

template<typename> struct A; // fine
template<int> struct B; // fine
template<typename F, F = nullptr> struct C; // fine
using AI = A<int>;
using BI = B<5>;
using CI = C<int, 5>;
using CD = C<void*>; // all fine
using Oops = C<char>; // not fine

您的案例只是用大声的int代替了Ftypename std::enable_if<...>::type之类的简单类型。我们不在乎传递的实际参数最终是否存在,所以这就是为什么它没有命名的原因。

template <class T,
         typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void do_stuff(T &t) {
    std::cout << "do_stuff integral\n";
}

插入T = inttypename std::enable_if<std::is_integral<T>::value>::type = void,因此第二个默认参数看起来像void* = nullptr,这意味着它是类型为void*的未命名参数,默认为{{1 }}。请注意,nullptr是非类型模板参数的类型的一部分。它不能用作类型模板参数的介绍者。另外,请注意,现代的C ++编写方式是

typename

其中// typename instead of class is more a style thing template<typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr> enable_if_t是别名,缩写为所有is_integral_v::value废话:

typename ...::type