Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between non-type template parameters in C++17 and C++11?

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.

like image 235
Ghasem Ramezani Avatar asked Nov 30 '20 16:11

Ghasem Ramezani


People also ask

Why do we use :: template template parameter?

Correct Option: D. It is used to adapt a policy into binary ones.

What are non-type parameters for templates?

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.

What is template type parameter?

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.

What is non-type parameter in template C++?

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.


2 Answers

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.

like image 172
aschepler Avatar answered Sep 22 '22 08:09

aschepler


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.

like image 22
Brian Bi Avatar answered Sep 25 '22 08:09

Brian Bi