Reputation: 15284
I have two version of 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 error:
int a[10];
int* a_it = my_begin(a);
error:
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 not working for NULL). I do understand that in template it requires explicit casting (in this case, from int
to void*
, but why the second one does not require it?
Another question, if I remove the whitespace between *
and =
, it also failed. Why is that?
Upvotes: 3
Views: 688
Reputation: 137315
§14.1 [temp.param]/p4 says:
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
.
Read literally, this disallows void*
template parameters altogether. void*
is an object pointer type but isn't a pointer to object type (§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 tovoid
does not have a pointer-to-object type, however, becausevoid
is not an object type. —end note ]
If we assume it's a defect and that the standard really meant to say "object pointer type", then using 0
and company is still disallowed by §14.3.2 [temp.arg.nontype]/p5 (emphasis added):
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
andnullptr
are valid template-arguments for a non-type template-parameter of type “pointer to int.” —end note ]
= 0
works for function default arguments because those are subject to the normal conversion rules, which allows an integer literal with value 0 to convert to a null pointer, rather than the special rules for template arguments.
if I remove the whitespace between * and =, it also failed. Why is that?
Maximum munch. If the whitespace is removed, *=
is a single token (the compound assignment operator). Just like in C++03 when you had to put a space between the >
s in std::vector<std::vector<int> >
.
Upvotes: 9