Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the C++20 standard say about usage of subojects as template non-type arguments?

The "Template non-type arguments" paragraph of the article „Template parameters and template arguments“ states:

The only exceptions are that non-type template parameters of reference or pointer type and non-static data members of reference or pointer type in a non-type template parameter of class type and its subobjects (since C++20) cannot refer to/be the address of

  • a temporary object (including one created during reference initialization);
  • a string literal;
  • the result of typeid;
  • the predefined variable __func__;
  • or a subobject (including non-static class member, base subobject, or array element) of one of the above (since C++20).

Emphasis is mine.

And below there is an example

template<int* p> class X {};
int a[10];
struct S
{
    int m;
    static int s;
} s;

X<&a[2]> x3;  // error: address of array element
X<&s.m> x4;   // error: address of non-static member
X<&s.s> x5;   // ok: address of static member
X<&S::s> x6;  // ok: address of static member

Basing on the quoted statement, the lines with the word error in the comments should be compileable by c++ compilers supporting c++20, because a[2] and s.m are neither temporary objects nor string literals nor results of typeid nor predefined variables __func__ nor subobjects of one of the above. In fact, gcc 11.1 compiles the code without errors, but clang 12.0.0 compiles the code with errors.

Further, the draft N4835 declares the following in the paragraph 13.4.2

A template-argument for a non-type template-parameter shall be a converted constant expression (7.7) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, or for each non-static data member of reference or pointer type in a non-type template-parameter of class type or subobject thereof, the reference or pointer value shall not refer to or be the address of (respectively):

  • a subobject (6.7.2),
  • a temporary object (6.7.7),
  • a string literal (5.13.5),—(2.4)the result of a typeid expression (7.6.1.7), or
  • a predefined __func__ variable (9.5.1).

and contains the mentioned example. Again emphasis is mine.

Taking into account this draft, clang works correctly and gcc does not, because a[2] and s.m are subobjects.

Digging deeper. The draft N4878 contains the following text in the paragraph 13.4.3

For a non-type template-parameter of reference or pointer type, or for each non-static data member of reference or pointer type in a non-type template-parameter of class type or subobject thereof, the reference or pointer value shall not refer to or be the address of (respectively):

  • a temporary object (6.7.7),
  • a string literal object (5.13.5),
  • the result of a typeid expression (7.6.1.8),
  • a predefined __func__ variable (9.5.1), or
  • a subobject (6.7.2) of one of the above.

and does not contain the example.

The quoted text in the beginning of this topic corresponds to the draft N4878 and accordingly the gcc works correctly and clang does not.

What does the C++20 standard say about usage of subojects as template non-type arguments? And which compiler does work in compliance with the standard?

like image 514
megabyte1024 Avatar asked Jun 06 '21 18:06

megabyte1024


People also ask

Can we use non-type parameters as arguments template?

Non-type template arguments are normally used to initialize a class or to specify the sizes of class members. For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.

What is a template argument C++?

In C++ this can be achieved using template parameters. 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 are non-type parameter 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 can be passed by non-type template parameters during compile time?

What can be passed by non-type template parameters during compile time? Explanation: Non-type template parameters provide the ability to pass a constant expression at compile time. The constant expression may also be an address of a function, object or static class member.


Video Answer


1 Answers

The wording changed as part of P1907R1, which was adopted as part of C++20. Note that the first draft you cited - N4835 - predates this adoption (that draft was published Oct 2019, and this paper was adopted the following month at the Belfast meeting in Nov 2019). The closest draft to C++20 is N4861, which you can also conveniently view in html form.

As a result, the following:

template<int* p> class X {};
int a[10];
struct S
{
    int m;
    static int s;
} s;

X<&a[2]> x3;
X<&s.m> x4;

is a valid C++20 program, since neither a[2] nor s.m are subobjects of any of: a temporary, a string literal, the result of a typeid expression, or __func__.


The cppreference example has already been updated to reflect this, where the comments now read:

X<&a[2]> x3;  // error (until C++20): address of array element
X<&s.m> x4;   // error (until C++20): address of non-static member
like image 200
Barry Avatar answered Nov 14 '22 23:11

Barry