Consider this code:
using func = int (*)(int, int);
template<func F>
void do_something(int first, int second) {}
int something(int first, int second) { return 42; }
void f()
{
constexpr auto function = something;
do_something<function>(10, 20);
}
Which is compiled and run with C++17 standard compatible compiler, but it's fail with C++11 standard:
error: no matching function for call to ‘do_something<function>(int, int)’
17 | do_something<function>(10, 20);
What is the difference between C++11 non-type template parameters and C++17 non-type template parameters? in §14.1.4 [temp.param][n3690]:
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.
And in §17.1.4 [temp.param][n4713]:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
(4.1) — integral or enumeration type,
(4.2) — pointer to object or pointer to function,
(4.3) — lvalue reference to object or lvalue reference to function,
(4.4) — pointer to member,
(4.5) — std::nullptr_t, or
(4.6) — a type that contains a placeholder type (10.1.7.4).
The only difference is:
< — a type that contains a placeholder type (10.1.7.4).
Which I don't think is related to my question because a placeholder type is something like auto
, and I sent a value to template not a placeholder type or a type.
Correct Option: D. It is used to adapt a policy into binary ones.
A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With