我有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)。我明白在模板中它需要显式转换(在这种情况下,从int
到void*
,但为什么第二个不需要呢?
另一个问题是,如果删除*
和=
之间的空格,它也会失败。那是为什么?
答案 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*)0
和nullptr
对于类型的非类型模板参数,是有效的模板参数 “指向int的指针。” - 结束记录]
= 0
适用于函数默认参数,因为它们遵循正常的转换规则,允许将值为0的整数文字转换为空指针,而不是模板参数的特殊规则。
如果我删除*和=之间的空格,它也会失败。那是为什么?
最大咀嚼。如果删除了空格,*=
是单个标记(复合赋值运算符)。就像在C ++ 03中一样,你必须在>
的{{1}}之间加一个空格。