c++ - 为什么 void* 作为模板参数作为函数参数而不是模板参数?

标签 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*,但为什么第二个不需要它?

另外一个问题,如果我去掉*=之间的空格,也是失败的。这是为什么?

最佳答案

§14.1 [temp.param]/p4 说:

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

  • integral or enumeration type,
  • pointer to object or pointer to function,
  • lvalue reference to object or lvalue reference to function,
  • pointer to member,
  • std::nullptr_t.

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

The type of a pointer to void or a pointer to an object type is called an object pointer type. [ Note: A pointer to void does not have a pointer-to-object type, however, because void is not an object type. —end note ]

如果我们假设它是一个缺陷并且标准真的意味着“对象指针类型”,那么使用 0并且 company 仍被 §14.3.2 [temp.arg.nontype]/p5(添加了强调)所禁止:

The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.

  • [...]
  • for a non-type template-parameter of type pointer to object, qualification conversions (4.4) and the array-to-pointer conversion (4.2) are applied; if the template-argument is of type std::nullptr_t, the null pointer conversion (4.10) is applied. [ Note: In particular, neither the null pointer conversion for a zero-valued integer literal (4.10) nor the derived-to-base conversion (4.10) are applied. Although 0 is a valid template-argument for a non-type template-parameter of integral type, it is not a valid template-argument for a non-type template-parameter of pointer type. However, both (int*)0 and nullptr are valid template-arguments for a non-type template-parameter of type “pointer to int.” —end note ]

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


if I remove the whitespace between * and =, it also failed. Why is that?

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

关于c++ - 为什么 void* 作为模板参数作为函数参数而不是模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26290770/

相关文章:

c++ - 使用模板函数继承类

c++ - 如何使 `std::is_empty_v<T> && sizeof(T) > 1` 为真的类型 T?

macos - 使用带有检查器的 Makefile 构建 clang 时出现链接器错误

c++ - const 成员函数中的互斥或原子

c++ - 这个模板类型推导和重载解析是如何工作的?

c++ - 为什么 std::forward 将左值和右值转换为右值引用?

c++ - 模板和#defines 的奇怪行为

c++ - 容器对象作为 (void*) 传递时的共享指针行为

c++ - 在 Gmock 的 EXPECT_CALL 之前使用 ON_CALL 时的奇怪行为

c++ - 访问冲突写入位置 0xcccccccc