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

tex*_*uce 3 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

但是第一个不起作用并给出错误:

int a[10];
int* a_it = my_begin(a);
Run Code Online (Sandbox Code Playgroud)

错误:

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>
Run Code Online (Sandbox Code Playgroud)

但第二个有效.当我在第一个中将0更改为nullptr时,它也可以工作(但仍然不能用于NULL).我确实理解在模板中它需要显式转换(在这种情况下,来自intto void*,但为什么第二个不需要它?

另一个问题是,如果我删除之间的空白*=,它也失败了.这是为什么?

T.C*_*.C. 9

§14.1[temp.param]/p4说:

非类型模板参数应具有以下之一(可选的cv限定)类型:

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

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

类型的指针的void或指向对象类型被称为对象的指针类型.[ 注意:指向void没有指向对象类型的指针,因为void它不是对象类型.- 结束说明 ]

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

对用作非类型模板参数的每个表达式执行以下转换.如果非类型模板参数无法转换为相应模板参数的类型,则程序格式错误.

  • [...]
  • 对于指向对象的类型指针的非类型模板参数,应用限定转换(4.4)和数组到指针转换(4.2); 如果template-argument是type std::nullptr_t,则应用空指针转换(4.10).[ 注意:特别是,既不应用零值整数文字(4.10)的空指针转换,也不应用衍生到基础转换(4.10).虽然0是一个有效的模板参数的非类型模板参数积分型的,它不是一个有效的模板参数的非类型 模板参数指针类型.然而,无论是(int*)0nullptr 是有效的模板参数类型的非类型模板参数"指针为int." - 注完 ]

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


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

最大的咀嚼.如果删除空格,*=则是单个标记(复合赋值运算符).就像在C++ 03中一样,你必须在>s 之间放置一个空格std::vector<std::vector<int> >.