为什么void * as template参数作为函数参数而不是模板参数?

时间:2014-10-10 01:56:07

标签: c++ templates c++11

我有my_begin的两个版本:

template<typename T, typename std::enable_if<std::is_array<T>::value>::type* = 0>
typename std::decay<T>::type my_begin(T& array) {
    return array;
}

template<typename T>
typename std::decay<T>::type my_begin(T& array, 
        typename std::enable_if<std::is_array<T>::value>::type* = 0) {
    return array;
}

然而,第一个不起作用并给出错误:

int a[10];
int* a_it = my_begin(a);

错误:

main.cpp:17:30: note:   template argument deduction/substitution failed:

main.cpp:16:80: error: could not convert template argument '0' to 'std::enable_if<true, void>::type* {aka void*}'

 template<typename T, typename std::enable_if<std::is_array<T>::value>::type* = 0>

但第二个有效。当我在第一个中将0更改为nullptr时,它也可以工作(但仍然不能用于NULL)。我明白在模板中它需要显式转换(在这种情况下,从intvoid*,但为什么第二个不需要呢?

另一个问题是,如果删除*=之间的空格,它也会失败。那是为什么?

1 个答案:

答案 0 :(得分:9)

§14.1[temp.param] / p4说:

  

非类型模板参数应具有以下之一   (可选择cv-qualified)类型:

     
      
  • 整数或枚举类型,
  •   
  • 指向对象或指向函数的指针,
  •   
  • 对对象的左值引用或对函数的左值引用,
  •   
  • 指向成员的指针,
  •   
  • std::nullptr_t
  •   

从字面上理解,这完全不允许void*模板参数。 void*对象指针类型,但不是指向对象类型的指针(§3.9.2[basic.compound] / p3):

  

指向void的指针的类型或指向对象类型的指针是   称为对象指针类型。 [注意:指向void的指针   但是,没有指向对象的类型,因为void不是   对象类型。 - 结束记录]

如果我们假设它是一个缺陷并且标准真的意味着说“对象指针类型”,那么使用0和公司仍然不允许§14.3.2[temp.arg.nontype] / p5(重点补充):

  

对用作a的每个表达式执行以下转换   非类型模板参数。如果不能使用非类型 template-argument   转换为相应的模板参数的类型然后   节目形成不良。

     
      
  • [...]
  •   
  • 表示对象类型指针的非类型模板参数,限定转换(4.4)和数组到指针的转换   (4.2)适用;如果 template-argument 的类型为std::nullptr_t,   应用空指针转换(4.10)。 [注意特别是   既不是零值整数文字的空指针转换   (4.10)也没有应用派生到基础的转换(4.10)。虽然   0是非类型模板参数的有效模板参数   对于非类型,它不是有效的 template-argument   指针类型的模板参数。但是,(int*)0nullptr   对于类型的非类型模板参数,是有效的模板参数   “指向int的指针。” - 结束记录]
  •   

= 0适用于函数默认参数,因为它们遵循正常的转换规则,允许将值为0的整数文字转换为空指针,而不是模板参数的特殊规则。


  

如果我删除*和=之间的空格,它也会失败。那是为什么?

最大咀嚼。如果删除了空格,*=是单个标记(复合赋值运算符)。就像在C ++ 03中一样,你必须在>的{​​{1}}之间加一个空格。