简体   繁体   中英

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 sm 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, thedraft 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 sm 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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM