Skip to content

P1907R1 Inconsistencies with non-type template parameters #3441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions papers/nxxxx.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ CWG motion 2: [P1234R5 "Paper name"](http://wg21.link/p1234r5), resolving 3 NB c

...

## Feature test macros

The feature test macro `__cpp_nontype_template_parameter_class` has been removed
to indicate that the feature added by [P0732R2](http://wg21.link/p0732r2)
is no longer present in the same form.

The value of the feature test macro `__cpp_nontype_template_args` has been increased
to `201911L` to indicate support for [P1907R1](http://wg21.link/p1907r1).

## Disposition of editorial NB comments on C++ 2020 CD1

Listed below are draft disposition for all comments that were
Expand Down
24 changes: 0 additions & 24 deletions source/classes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -6700,30 +6700,6 @@
the defaulted three-way comparison operator function is defined as deleted.
\end{note}

\pnum
\indextext{structural comparison operator|see{operator, structural comparison}}%
A type \tcode{C} has \defnadj{strong structural}{equality} if,
given a glvalue \tcode{x} of type \tcode{const C}, either:
\begin{itemize}
\item
\tcode{C} is a non-class type and
\tcode{x <=> x} is a valid expression
of type \tcode{std::strong_ordering} or \tcode{std::strong_equality}, or

\item
\tcode{C} is a class type
where all of the following hold:
\begin{itemize}
\item All of \tcode{C}'s base class subobjects and non-static data members
have strong structural equality.
\item \tcode{C} has no mutable or volatile non-static data members.
\item At the end of the definition of \tcode{C},
overload resolution performed for the expression \tcode{x == x} succeeds and
finds either a friend or public member \tcode{==} operator
that is defined as defaulted in the definition of \tcode{C}.
\end{itemize}
\end{itemize}

\pnum
The direct base class subobjects of \tcode{C},
in the order of their declaration in the \grammarterm{base-specifier-list} of \tcode{C},
Expand Down
3 changes: 1 addition & 2 deletions source/preprocessor.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1668,9 +1668,8 @@
\defnxname{cpp_modules} & \tcode{201907L} \\ \rowsep
\defnxname{cpp_namespace_attributes} & \tcode{201411L} \\ \rowsep
\defnxname{cpp_noexcept_function_type} & \tcode{201510L} \\ \rowsep
\defnxname{cpp_nontype_template_args} & \tcode{201411L} \\ \rowsep
\defnxname{cpp_nontype_template_args} & \tcode{201911L} \\ \rowsep
\defnxname{cpp_nontype_template_parameter_auto} & \tcode{201606L} \\ \rowsep
\defnxname{cpp_nontype_template_parameter_class} & \tcode{201806L} \\ \rowsep
\defnxname{cpp_nsdmi} & \tcode{200809L} \\ \rowsep
\defnxname{cpp_range_based_for} & \tcode{201603L} \\ \rowsep
\defnxname{cpp_raw_strings} & \tcode{200710L} \\ \rowsep
Expand Down
183 changes: 110 additions & 73 deletions source/templates.tex
Original file line number Diff line number Diff line change
Expand Up @@ -367,28 +367,31 @@
A non-type \grammarterm{template-parameter}
shall have one of the following (optionally cv-qualified) types:
\begin{itemize}
\item a literal type that
has strong structural equality\iref{class.compare.default},

\item an lvalue reference type,

\item a structural type (see below),
\item a type that contains a placeholder type\iref{dcl.spec.auto}, or

\item a placeholder for a deduced class type\iref{dcl.type.class.deduct}.
\end{itemize}

\pnum
\begin{note}
Other types are disallowed either explicitly below or implicitly by
the rules governing the form of
\grammarterm{template-argument}{s}\iref{temp.arg}.
\end{note}
The top-level
\grammarterm{cv-qualifier}{s}
on the
\grammarterm{template-parameter}
are ignored when determining its type.

\pnum
A \defnadj{structural}{type} is one of the following:
\begin{itemize}
\item a scalar type, or
\item an lvalue reference type, or
\item a literal class type with the following properties:
\begin{itemize}
\item
all base classes and non-static data members are public and non-mutable and
\item
the types of all bases classes and non-static data members are
structural types or (possibly multi-dimensional) array thereof.
\end{itemize}
\end{itemize}

\pnum
An \grammarterm{id-expression} naming
a non-type \grammarterm{template-parameter} of class type \tcode{T}
Expand All @@ -399,6 +402,7 @@
to the type of the \grammarterm{template-parameter}.
All such template parameters in the program of the same type
with the same value denote the same template parameter object.
A template parameter object shall have constant destruction\iref{expr.const}.
\begin{note}
If an \grammarterm{id-expression} names
a non-type non-reference \grammarterm{template-parameter},
Expand All @@ -409,9 +413,9 @@
\begin{example}
\begin{codeblock}
using X = int;
struct A { friend bool operator==(const A&, const A&) = default; };
struct A {};
template<const X& x, int i, A a> void f() {
i++; // error: change of template-parameter value
i++; // error: change of \grammarterm{template-parameter} value

&x; // OK
&i; // error: address of non-reference template-parameter
Expand All @@ -424,16 +428,17 @@
\end{example}

\pnum
\begin{note}
A non-type
\grammarterm{template-parameter}
shall not be declared to have floating-point or void type.
cannot be declared to have type \cv{} \tcode{void}.
\begin{example}
\begin{codeblock}
template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK
template<void v> class X; // error
template<void* pv> class Y; // OK
\end{codeblock}
\end{example}
\end{note}

\pnum
A non-type
Expand Down Expand Up @@ -1184,26 +1189,27 @@
for a non-type \grammarterm{template-parameter}
shall be a converted constant expression\iref{expr.const}
of the type of the \grammarterm{template-parameter}.
\begin{note}
If the \grammarterm{template-argument}
represents a set of overloaded functions
(or a pointer or member pointer to such),
the matching function is selected from the set\iref{over.over}.
\end{note}

\pnum
For a non-type \grammarterm{template-parameter} of reference or pointer type,
or for each non-static data member of reference or pointer type
in a non-type \grammarterm{template-parameter} of class type or subobject thereof,
the reference or pointer value shall not refer to
or be the address of (respectively):
\begin{itemize}
\item a subobject\iref{intro.object},
\item a temporary object\iref{class.temporary},
\item a string literal\iref{lex.string},
\item the result of a \tcode{typeid} expression\iref{expr.typeid}, or
\item a predefined \mname{func} variable\iref{dcl.fct.def.general}.
\item the result of a \tcode{typeid} expression\iref{expr.typeid},
\item a predefined \mname{func} variable\iref{dcl.fct.def.general}, or
\item a subobject\iref{intro.object} of one of the above.
\end{itemize}

\begin{note}
If the \grammarterm{template-argument}
represents a set of overloaded functions
(or a pointer or member pointer to such),
the matching function is selected from the set\iref{over.over}.
\end{note}

\pnum
\begin{example}
\begin{codeblock}
Expand All @@ -1228,9 +1234,10 @@
A<&f> a; // selects \tcode{f(int)}

template<auto n> struct B { @\commentellip@ };
B<5> b1; // OK: template parameter type is \tcode{int}
B<'a'> b2; // OK: template parameter type is \tcode{char}
B<2.5> b3; // error: template parameter type cannot be \tcode{double}
B<5> b1; // OK, template parameter type is \tcode{int}
B<'a'> b2; // OK, template parameter type is \tcode{char}
B<2.5> b3; // OK, template parameter type is \tcode{double}
B<void(0)> b4; // error: template parameter type cannot be \tcode{void}
\end{codeblock}
\end{example}

Expand All @@ -1245,40 +1252,21 @@
@\commentellip@
};

X<const char*, "Studebaker"> x; // error: string literal as template-argument
X<const char*, "Studebaker"> x; // error: string literal as \grammarterm{template-argument}
X<const char*, "Knope" + 1> x2; // error: subobject of string literal as \grammarterm{template-argument}

const char p[] = "Vivisectionist";
X<const char*, p> y; // OK

struct A {
constexpr A(const char*) {}
friend bool operator==(const A&, const A&) = default;
};

X<A, "Pyrophoricity"> z; // OK, string literal is a constructor argument to \tcode{A}
\end{codeblock}
\end{example}
\end{note}

\pnum
\begin{note}
The address of an array element or non-static data member is not an acceptable
\grammarterm{template-argument}.
\begin{example}
\begin{codeblock}
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
\end{codeblock}
\end{example}
\end{note}

\pnum
\begin{note}
A temporary object
Expand All @@ -1291,10 +1279,16 @@
\begin{codeblock}
template<const int& CRI> struct B { @\commentellip@ };

B<1> b2; // error: temporary would be required for template argument
B<1> b1; // error: temporary would be required for template argument

int c = 1;
B<c> b1; // OK
B<c> b2; // OK

struct X { int n; };
struct Y { const int &r; };
template<Y y> struct C { @\commentellip@ };
C<Y{X{1}.n}> c; // error: subobject of temporary object used to initialize
// reference member of template parameter
\end{codeblock}
\end{example}
\end{note}
Expand Down Expand Up @@ -1939,25 +1933,68 @@
Two \grammarterm{template-id}{s} refer to the same
class, function, or variable if
\begin{itemize}
\item {their \grammarterm{template-name}{s},
\grammarterm{operator-function-id}{s}, or \grammarterm{literal-operator-id}{s}
refer to the same template and}
\item {their corresponding type \grammarterm{template-argument}{s} are the
same type and}
\item {their corresponding non-type \grammarterm{template-argument}{s} of
pointer-to-member type refer to the same class member or are both the null member
pointer value and}
\item {their corresponding non-type \grammarterm{template-argument}{s} of
reference type refer to the same object or function and}
\item {their remaining corresponding
non-type \grammarterm{template-argument}{s}
have the same type and value
after conversion to the type of the \grammarterm{template-parameter},
where they are considered to have the same value if they compare equal
with the \tcode{==} operator\iref{expr.eq}, and}
\item {their corresponding template \grammarterm{template-argument}{s} refer
to the same template.}
\item
their \grammarterm{template-name}{s},
\grammarterm{operator-function-id}{s}, or
\grammarterm{literal-operator-id}{s}
refer to the same template, and

\item
their corresponding type \grammarterm{template-argument}{s}
are the same type, and

\item
their corresponding non-type \grammarterm{template-argument}{s}
are template-argument-equivalent (see below)
after conversion to the type of the \grammarterm{template-parameter}, and

\item
their corresponding template \grammarterm{template-argument}{s}
refer to the same template.
\end{itemize}

\pnum
Two values are \defn{template-argument-equivalent} if
they are of the same type and
\begin{itemize}
\item
they are of integral type and their values are the same, or

\item
they are of floating-point type and their values are identical, or

\item
they are of type \tcode{std::nullptr_t}, or

\item
they are of enumeration type and their values are the same,%
\footnote{The identity of enumerators is not preserved.} or

\item
they are of pointer type and they have the same pointer value, or

\item
they are of pointer-to-member type and they refer to the same class member
or are both the null member pointer value, or

\item
they are of reference type and they refer to the same object or function, or

\item
they are of array type and their corresponding elements are template-argument-equivalent,%
\footnote{An array as a \grammarterm{template-parameter} decays to a pointer.} or

\item
they are of union type and either
they both have no active member or
they have the same active member and their active members are template-argument-equivalent, or

\item
they are of class type and
their corresponding direct subobjects and reference members are template-argument-equivalent.
\end{itemize}

\pnum
\begin{example}
\begin{codeblock}
template<class E, int size> class buffer { @\commentellip@ };
Expand Down