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

标签 c++ templates c++11 overloading 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) {}

并且可以正确区分这两个调用:

Add(1);
Add(1.0);

如果编译以下代码会导致重新定义 Add() 错误?

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) {}

变成:

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) {}

现在移除模板参数值:

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) {}

变成:

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) {}

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

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

当您使用像上面这样的非类型模板参数时,您会更改模板签名而不仅仅是模板参数值。当您使用上述类型模板参数时,您只需更改模板参数值。

关于c++ - SFINAE 在类型和非类型模板参数的情况下工作方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36499008/

相关文章:

c++ - 添加要映射的对象的唯一指针

templates - 将conf文件嵌入到helm图表中

templates - Jade 模板作为 html 的预处理器

c++ - 在子类中调用基类的模板函数是否合法?

c++ - 为什么将 operator void*() 转换函数添加到 C++ 流类中?

c++11 - 何时使用 ostream_iterator

c++ - Pthread_mutex_lock 返回访问错误

c++ - 编译 libjpeg

c++ - Mat.at 函数抛出异常

c++ - 使用类型转换创建对 unique_ptr 中对象的引用