Why does void * as a template parameter work as a function parameter and not a template parameter?
I have two versions 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;
}
and
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;
}
However, the first one does not work and gives an error:
int a[10];
int* a_it = my_begin(a);
Mistake:
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>
But the second one works. When I change 0 in the first one to nullptr it works too (but still doesn't work for NULL). I understand that the template requires explicit casting (in this case from int
to void*
, but why doesn't the second one?
Another question, if I remove the space between *
and =
, it also fails. Why is this?
source to share
ยง14.1 [temp.param] / p4 says:
A non-type template parameter must be one of the following (optionally cv-qualified):
- integral or enumerated type,
- a pointer to an object or a pointer to a function,
- an lvalue reference to an object reference or an lvalue to a function,
- a pointer to a member,
std::nullptr_t
...
Read literally, this completely excludes template parameters void*
. void*
- the type of an object pointer, but is not a pointer to an object type (ยง.3.9.2 [basic.compound] / p3):
A pointer type to
void
or pointer to an object type is called an object pointer type. [Note: Pointer tovoid
does not have pointer-object type, however, becausevoid
it is not object type. -end note]
If we assume that this is a defect and that the standard does mean "object pointer type", then using 0
and company is still prohibited in ยง14.3.2 [temp.arg.nontype] / p5 (italicized):
The following conversions are performed for each expression used as a non-type template-argument. If the non-type template argument cannot be converted to the type of the corresponding template parameter, then the program is ill-formed.
- [...]
- for an atypical template-parameter of a type pointer to an object, qualification conversion (4.4) and conversion between arrays and pointers (4.2); if template is of type
std::nullptr_t
, null pointer conversion (4.10) is applied. [Note: In particular, neither a null pointer conversion for a null integer literal (4.10), nor a derived base conversion (4.10). 0 is a valid template argument for a non-template-parameter type of integer type, this is not a valid template-argument for a non-template-parameter type of pointer type. However(int*)0
, both andnullptr
are valid template-arguments for an atypical template-parameter of type "pointer to int". -end note]
= 0
works for default arguments because they obey the normal conversion rules that allow an integer literal with a value of 0 to be converted to a null pointer, rather than special rules for template arguments.
If I remove the space between * and =, it also fails. Why is this?
Maximum munch. If the space is removed, *=
is the only token (compound assignment operator). As of C ++ 03, when you needed to place a space between >
in std::vector<std::vector<int> >
.
source to share