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?

+3


source to share


1 answer


ยง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 to void

does not have pointer-object type, however, because void

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 and nullptr

    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> >

.

+9


source







All Articles