What is the difference between non-type template parameters in C++17 and C++11?
The relevant difference is in the requirements on allowed template arguments (not template parameters) in [temp.arg.nontype].
C++11:
A template-argument for a non-type, non-template template-parameter shall be one of:
- ...
- a constant expression that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
&
id-expression, except that the&
may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or- ...
C++17:
A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
- a subobject,
- a temporary object,
- a string literal,
- the result of a
typeid
expression, or- a predefined
__func__
variable.
In C++11, the template-argument function
is not in the form &
id-expression, and the name does not refer to the function something
. It refers to a variable of type int (*const)(int, int)
, whose value points at something
. (And do_something<&function>
wouldn't help, because now you have a pointer to pointer to function, which won't convert to the pointer to function type.)
In C++17, the syntax requirement is gone, and the restriction is a more relaxed purely semantic requirement on what objects can't be pointed at or referenced.
C++11 [temp.arg.nontype]/1:
A template-argument for a non-type, non-template template-parameter shall be one of:
- [...]
- the name of a non-type template-parameter; or
- a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
&
id-expression, except that the&
may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or- [...]
In other words, the form that a non-type template argument may take in C++11, in the case of a pointer, is heavily restricted. You can directly name the entity pointed to, as in &something
, or, since this is a function, you may omit the &
and allow the function-to-pointer conversion to take place, but you cannot use the name of an object that contains the pointer value, even if it is a constexpr
object.
In C++17, almost all restrictions of this type were removed. In particular, a template argument for a non-type template parameter of function pointer type can be any converted constant expression of the appropriate function pointer type.