SFINAE 在类型和非类型模板参数的情况下工作方式不同

2024-01-08

为什么这段代码有效:

template<
    typename T, 
    std::enable_if_t<std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}

template<
    typename T, 
    std::enable_if_t<!std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}

并能正确区分这两个调用:

Add(1);
Add(1.0);

而下面的代码如果编译结果是重新定义 Add() error?

template<
    typename T, 
    typename = typename std::enable_if<std::is_same<T, int>::value, T>::type>
void Add(T) {}

template<
    typename T, 
    typename = typename std::enable_if<!std::is_same<T, int>::value, T>::type>
void Add(T) {}

所以如果模板参数是类型,那么我们就重新定义了函数,如果它是非类型,那么一切都可以。


SFINAE 是关于替代的。那么就让我们来代替吧!

template<
  typename T, 
  std::enable_if_t<std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}

template<
  typename T, 
  std::enable_if_t<!std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}

Becomes:

template<
  class T=int, 
  int* = nullptr>
void Add(int) {}

template<
  class T=int, 
  Substitution failure* = nullptr>
void Add(int) {

template<
  class T=double, 
  Substitution failure* = nullptr>
void Add(double) {}

template<
  class T=double
  double* = nullptr>
void Add(double) {}

删除我们得到的失败:

template<
  class T=int, 
  int* = nullptr>
void Add(int) {}
template<
  class T=double
  double* = nullptr>
void Add(double) {}

Now 删除模板参数值:

template<
  class T, 
  int*>
void Add(T) {}
template<
  class T
  double*>
void Add(T) {}

这些是不同的模板。

现在搞砸的是:

template<
  typename T, 
  typename = typename std::enable_if<std::is_same<T, int>::value, T>::type>
void Add(T) {}

template<
  typename T, 
  typename = typename std::enable_if<!std::is_same<T, int>::value, T>::type>
void Add(T) {}

Becomes:

template<
  typename T=int, 
  typename =int>
void Add(int) {}

template<
  typename int, 
  typename = Substitution failure >
void Add(int) {}

template<
  typename T=double, 
  typename = Substitution failure >
void Add(double) {}

template<
  typename T=double, 
  typename = double>
void Add(double) {}

排除故障:

template<
  typename T=int, 
  typename =int>
void Add(int) {}
template<
  typename T=double, 
  typename = double>
void Add(double) {}

现在模板参数值:

template<
  typename T, 
  typename>
void Add(T) {}
template<
  typename T, 
  typename>
void Add(T) {}

这些是相同的模板签名。这是不允许的,会产生错误。

为什么会有这样的规定呢?超出了这个答案的范围。我只是展示这两种情况的不同之处,并断言标准以不同的方式对待它们。

当您使用如上所述的非类型模板参数时,您将更改模板签名而不仅仅是模板参数值。当您使用如上所述的类型模板参数时,您只需更改模板参数值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SFINAE 在类型和非类型模板参数的情况下工作方式不同 的相关文章

随机推荐