diff --git a/source/basic.tex b/source/basic.tex index 9b12f0d8a5..a2b6c8163c 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -865,6 +865,32 @@ \end{itemize} \end{note} +\pnum +Two non-static member functions have +\defnadjx{corresponding}{object parameters}{object parameter} if: +\begin{itemize} +\item +exactly one is an implicit object member function +with no \grammarterm{ref-qualifier} and +the types of their object parameters\iref{dcl.fct}, +after removing top-level references, +are the same, or +\item +their object parameters have the same type. +\end{itemize} +Two non-static member function templates have +\defnadjx{corresponding}{object parameters}{object parameter} if: +\begin{itemize} +\item +exactly one is an implicit object member function +with no \grammarterm{ref-qualifier} and +the types of their object parameters, +after removing any references, +are equivalent, or +\item +the types of their object parameters are equivalent. +\end{itemize} + \pnum Two declarations \defn{correspond} if they (re)introduce the same name, @@ -885,7 +911,7 @@ each declares a function or function template, except when \begin{itemize} \item -both declare functions with the same parameter-type-list, +both declare functions with the same non-object-parameter-type-list, \begin{footnote} An implicit object parameter\iref{over.match.funcs} is not part of the parameter-type-list. @@ -893,17 +919,15 @@ equivalent\iref{temp.over.link} trailing \grammarterm{requires-clause}s (if any, except as specified in \ref{temp.friend}), and, if both are non-static members, -the same \grammarterm{cv-qualifier}s (if any) and -\grammarterm{ref-qualifier} (if both have one), or +they have corresponding object parameters, or \item both declare function templates with equivalent -parameter-type-lists, +non-object-parameter-type-lists, return types (if any), \grammarterm{template-head}s, and trailing \grammarterm{requires-clause}s (if any), and, if both are non-static members, -the same \grammarterm{cv-qualifier}s (if any) and -\grammarterm{ref-qualifier} (if both have one). +they have corresponding object parameters. \end{itemize} \end{itemize} \begin{note} @@ -923,16 +947,23 @@ \begin{codeblock} typedef int Int; enum E : int { a }; -void f(int); // \#1 -void f(Int) {} // defines \#1 -void f(E) {} // OK: another overload +void f(int); // \#1 +void f(Int) {} // defines \#1 +void f(E) {} // OK: another overload struct X { static void f(); - void f() const; // error: redeclaration + void f() const; // error: redeclaration void g(); - void g() const; // OK - void g() &; // error: redeclaration + void g() const; // OK + void g() &; // error: redeclaration + + void h(this X&, int); + void h(int) &&; // OK: another overload + void j(this const X&); + void j() const&; // error: redeclaration + void k(); + void k(this X&); // error: redeclaration }; \end{codeblock} \end{example} diff --git a/source/classes.tex b/source/classes.tex index 78214133eb..48df52ca42 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -997,7 +997,7 @@ \indextext{member function!volatile}% \indextext{member function!const volatile}% \begin{note} -A non-static member function can be declared with +An implicit object member function can be declared with \grammarterm{cv-qualifier}{s}, which affect the type of the \keyword{this} pointer\iref{expr.prim.this}, and/or a \grammarterm{ref-qualifier}\iref{dcl.fct}; @@ -1005,7 +1005,7 @@ \end{note} \pnum -A non-static member function may be declared +An implicit object member function may be declared virtual\iref{class.virtual} or pure virtual\iref{class.abstract}. \rSec2[special]{Special member functions} @@ -2487,7 +2487,7 @@ \nontermdef{conversion-declarator}\br ptr-operator \opt{conversion-declarator} \end{bnf} -shall have no parameters and +shall have no non-object parameters and specifies a conversion from \tcode{X} to the type specified by the \grammarterm{conversion-type-id}, interpreted as a \grammarterm{type-id}\iref{dcl.name}. diff --git a/source/declarations.tex b/source/declarations.tex index b50ee5256f..ebd6c36ee1 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -3435,10 +3435,10 @@ \begin{bnf} \nontermdef{parameter-declaration}\br - \opt{attribute-specifier-seq} decl-specifier-seq declarator\br - \opt{attribute-specifier-seq} decl-specifier-seq declarator \terminal{=} initializer-clause\br - \opt{attribute-specifier-seq} decl-specifier-seq \opt{abstract-declarator}\br - \opt{attribute-specifier-seq} decl-specifier-seq \opt{abstract-declarator} \terminal{=} initializer-clause + \opt{attribute-specifier-seq} \opt{\keyword{this}} decl-specifier-seq declarator\br + \opt{attribute-specifier-seq} \opt{\keyword{this}} decl-specifier-seq declarator \terminal{=} initializer-clause\br + \opt{attribute-specifier-seq} \opt{\keyword{this}} decl-specifier-seq \opt{abstract-declarator}\br + \opt{attribute-specifier-seq} \opt{\keyword{this}} decl-specifier-seq \opt{abstract-declarator} \terminal{=} initializer-clause \end{bnf} The optional \grammarterm{attribute-specifier-seq} in a \grammarterm{parameter-declaration} @@ -3547,6 +3547,66 @@ \end{codeblock} \end{example} +\pnum +An \defn{explicit-object-parameter-declaration} is +a \grammarterm{parameter-declaration} with a \keyword{this} specifier. +An explicit-object-parameter-declaration shall appear only as +the first \grammarterm{parameter-declaration} of +a \grammarterm{parameter-declaration-list} of either: +\begin{itemize} +\item +a \grammarterm{member-declarator} +that declares a member function\iref{class.mem}, or +\item +a \grammarterm{lambda-declarator}\iref{expr.prim.lambda}. +\end{itemize} +A \grammarterm{member-declarator} with an explicit-object-parameter-declaration +shall not include +a \grammarterm{ref-qualifier} or a \grammarterm{cv-qualifier-seq} and +shall not be declared \keyword{static} or \keyword{virtual}. +\begin{example} +\begin{codeblock} +struct C { + void f(this C& self); + template void g(this Self&& self, int); + + void h(this C) const; // error: \tcode{const} not allowed here +}; + +void test(C c) { + c.f(); // OK, calls \tcode{C::f} + c.g(42); // OK, calls \tcode{C::g} + std::move(c).g(42); // OK, calls \tcode{C::g} +} +\end{codeblock} +\end{example} + +\pnum +A function parameter declared with an explicit-object-parameter-declaration +is an \defnadj{explicit object}{parameter}. +An explicit object parameter shall not be +a function parameter pack\iref{temp.variadic}. +An \defnadj{explicit object}{member function} is a non-static member function +with an explicit object parameter. +An \defnadj{implicit object}{member function} is a non-static member function +without an explicit object parameter. + +\pnum +The \defnadj{object}{parameter} of a non-static member function is either +the explicit object parameter or +the implicit object parameter\iref{over.match.funcs}. + +\pnum +A \defnadj{non-object}{parameter} is a function parameter +that is not the explicit object parameter. +The \defn{non-object-parameter-type-list} of a member function is +the parameter-type-list of that function with the explicit object parameter, +if any, omitted. +\begin{note} +The non-object-parameter-type-list consists of +the adjusted types of all the non-object parameters. +\end{note} + \pnum A function type with a \grammarterm{cv-qualifier-seq} or a \grammarterm{ref-qualifier} (including a type named by @@ -6378,19 +6438,19 @@ \tcode{std::coroutine_traits::promise_type}, where \tcode{R} is the return type of the function, and -$\tcode{P}_1 \dotsc \tcode{P}_n$ are the sequence of types of the function parameters, -preceded by the type of the implicit object parameter\iref{over.match.funcs} +$\tcode{P}_1 \dotsc \tcode{P}_n$ are the sequence of types of the non-object function parameters, +preceded by the type of the object parameter\iref{dcl.fct} if the coroutine is a non-static member function. The promise type shall be a class type. \pnum In the following, $\tcode{p}_i$ is an lvalue of type $\tcode{P}_i$, where -$\tcode{p}_1$ denotes \tcode{*this} and -$\tcode{p}_{i+1}$ denotes the $i^\textrm{th}$ function parameter +$\tcode{p}_1$ denotes the object parameter and +$\tcode{p}_{i+1}$ denotes the $i^\text{th}$ non-object function parameter for a non-static member function, and $\tcode{p}_i$ denotes -the $i^\textrm{th}$ function parameter otherwise. +the $i^\text{th}$ function parameter otherwise. For a non-static member function, $\tcode{q}_1$ is an lvalue that denotes \tcode{*this}; any other $\tcode{q}_i$ is an lvalue diff --git a/source/expressions.tex b/source/expressions.tex index 0234e1579b..cb59ca307a 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1194,7 +1194,7 @@ \pnum \indextext{\idxcode{this}}% -The keyword \keyword{this} names a pointer to the object for which a non-static member +The keyword \keyword{this} names a pointer to the object for which an implicit object member function\iref{class.mfct.non-static} is invoked or a non-static data member's initializer\iref{class.mem} is evaluated. @@ -1213,8 +1213,10 @@ between the optional \grammarterm{cv-qualifier-seq} and the end of the \grammarterm{function-definition}, \grammarterm{member-declarator}, or \grammarterm{declarator}. It shall not appear within -the declaration of a static member function of the current class (although its type and value category -are defined within a static member function as they are within a non-static +the declaration of either +a static member function or an explicit object member function +of the current class (although its type and value category +are defined within such member functions as they are within an implicit object member function). \begin{note} This is because declaration matching does not @@ -1450,7 +1452,7 @@ the type of a class member access expression\iref{expr.ref} naming the non-static data member that would be declared for such a capture -in the closure object of +in the object parameter\iref{dcl.fct} of the function call operator of the innermost such intervening \grammarterm{lambda-expression}. \begin{note} If that \grammarterm{lambda-expression} is not declared \keyword{mutable}, @@ -1688,6 +1690,10 @@ In the \grammarterm{decl-specifier-seq} of the \grammarterm{lambda-declarator}, each \grammarterm{decl-specifier} shall be one of \keyword{mutable}, \keyword{constexpr}, or \keyword{consteval}. +If the \grammarterm{lambda-declarator} contains +an explicit object parameter\iref{dcl.fct}, +then no \grammarterm{decl-specifier} in the \grammarterm{decl-specifier-seq} +shall be \keyword{mutable}. \begin{note} The trailing \grammarterm{requires-clause} is described in \ref{dcl.decl}. \end{note} @@ -1792,6 +1798,40 @@ { std::cout << v1 << v2 << v3; } ); auto q = p(1, 'a', 3.14); // OK: outputs \tcode{1a3.14} q(); // OK: outputs \tcode{1a3.14} + +auto fact = [](this auto self, int n) -> int { // OK: explicit object parameter + return (n <= 1) ? 1 : n * self(n-1); +}; +std::cout << fact(5); // OK: outputs 120 +\end{codeblock} +\end{example} + +\pnum +Given a lambda with a \grammarterm{lambda-capture}, +the type of the explicit object parameter, if any, +of the lambda's function call operator +(possibly instantiated from a function call operator template) +shall be either: +\begin{itemize} +\item +the closure type, +\item +a class type derived from the closure type, or +\item +a reference to a possibly cv-qualified such type. +\end{itemize} +\begin{example} +\begin{codeblock} +struct C { + template + C(T); +}; + +void func(int i) { + int x = [=](this auto&&) { return i; }(); // OK + int y = [=](this C) { return i; }(); // error + int z = [](this C) { return 42; }(); // OK +} \end{codeblock} \end{example} @@ -1799,7 +1839,10 @@ The function call operator or operator template is declared \keyword{const}~(\ref{class.mfct.non-static}) if and only if the \grammarterm{lambda-expression}'s \grammarterm{parameter-declaration-clause} is not -followed by \keyword{mutable}. It is neither virtual nor declared \tcode{volatile}. Any +followed by \keyword{mutable} and +the \grammarterm{lambda-declarator} does not contain +an explicit object parameter. +It is neither virtual nor declared \tcode{volatile}. Any \grammarterm{noexcept-specifier} specified on a \grammarterm{lambda-expression} applies to the corresponding function call operator or operator template. An \grammarterm{attribute-specifier-seq} in a \grammarterm{lambda-declarator} appertains @@ -3082,6 +3125,10 @@ When a function is called, each parameter\iref{dcl.fct} is initialized~(\ref{dcl.init}, \ref{class.copy.ctor}) with its corresponding argument. +If the function is an explicit object member function and +there is an implied object argument\iref{over.call.func}, +the list of provided arguments is preceded by the implied object argument +for the purposes of this correspondence. If there is no corresponding argument, the default argument for the parameter is used. \begin{example} @@ -3090,7 +3137,7 @@ int x = f(); // error: no argument for second function parameter \end{codeblock} \end{example} -If the function is a non-static member +If the function is an implicit object member function, the \keyword{this} parameter of the function\iref{expr.prim.this} is initialized with a pointer to the object of the call, converted as if by an explicit type conversion\iref{expr.cast}. @@ -4337,11 +4384,13 @@ \begin{itemize} \item If the operand is a \grammarterm{qualified-id} naming a non-static or variant member \tcode{m} -of some class \tcode{C}, the result has type ``pointer to member +of some class \tcode{C}, other than an explicit object member function, the result has type ``pointer to member of class \tcode{C} of type \tcode{T}'' and designates \tcode{C::m}. \item Otherwise, the result has type ``pointer to \tcode{T}'' and points to the designated object\iref{intro.memory} or function\iref{basic.compound}. +If the operand names an explicit object member function\iref{dcl.fct}, +the operand shall be a \grammarterm{qualified-id}. \begin{note} In particular, taking the address of a variable of type ``\cv{}~\tcode{T}'' yields a pointer of type ``pointer to \cv{}~\tcode{T}''. diff --git a/source/overloading.tex b/source/overloading.tex index 5b1ce655f6..e5a980808e 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -53,7 +53,7 @@ well the arguments match the parameter-type-list of the candidate function, how well (for non-static member functions) the object -matches the implicit object parameter, +matches the object parameter, and certain other properties of the candidate function. \begin{note} The function selected by overload resolution is not @@ -155,13 +155,13 @@ The set of candidate functions can contain both member and non-member functions to be resolved against the same argument list. So that argument and parameter lists are comparable within this -heterogeneous set, a member function is considered to have an +heterogeneous set, a member function that does not have an explicit object parameter is considered to have an extra first parameter, called the \defn{implicit object parameter}, which represents the object for which the member function has been called. For the purposes of overload resolution, both static and -non-static member functions have an implicit object parameter, +non-static member functions have an object parameter, but constructors do not. \pnum @@ -172,7 +172,7 @@ the object to be operated on. \pnum -For non-static member functions, the type of the implicit object +For implicit object member functions, the type of the implicit object parameter is \begin{itemize} \item ``lvalue reference to \cv{}~\tcode{X}'' for functions declared @@ -194,13 +194,14 @@ function of class \tcode{X}, the extra parameter is assumed to have type -``reference to +``lvalue reference to \tcode{const X}''. \end{example} -For conversion functions, the function is considered to be a member of the +For conversion functions that are implicit object member functions, +the function is considered to be a member of the class of the implied object argument for the purpose of defining the type of the implicit object parameter. -For non-conversion functions +For non-conversion functions that are implicit object member functions nominated by a \grammarterm{using-declaration} in a derived class, the function is considered to be a member of the derived class for the purpose of defining @@ -223,7 +224,7 @@ no user-defined conversions can be applied to achieve a type match with it. \indextext{implied object argument!non-static member function and}% -For non-static member functions declared without a \grammarterm{ref-qualifier}, +For implicit object member functions declared without a \grammarterm{ref-qualifier}, even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be @@ -478,6 +479,36 @@ \end{footnote} if overload resolution selects a non-static member function, the call is ill-formed. +\begin{example} +\begin{codeblock} +struct C { + void a(); + void b() { + a(); // OK, \tcode{(*this).a()} + } + + void f(this const C&); + void g() const { + f(); // OK, \tcode{(*this).f()} + f(*this); // error: no viable candidate for \tcode{(*this).f(*this)} + this->f(); // OK + } + + static void h() { + f(); // error: contrived object argument, but overload resolution + // picked a non-static member function + f(C{}); // error: no viable candidate + C{}.f(); // OK + } + + void k(this int); + operator int() const; + void m(this const C& c) { + c.k(); // OK + } +}; +\end{codeblock} +\end{example} \rSec4[over.call.object]{Call to object of class type} @@ -545,7 +576,7 @@ \begin{note} When comparing the call against the function call operators, the implied object -argument is compared against the implicit object parameter of the +argument is compared against the object parameter of the function call operator. When comparing the call against a surrogate call function, the implied object argument is compared @@ -738,7 +769,7 @@ For all other operators, the rewritten candidate set is empty. \end{itemize} \begin{note} -A candidate synthesized from a member candidate has its implicit +A candidate synthesized from a member candidate has its object parameter as the second parameter, thus implicit conversions are considered for the first, but not for the second, parameter. \end{note} @@ -980,7 +1011,7 @@ expression. \begin{note} This argument will be compared against -the first parameter of the constructors and against the implicit +the first parameter of the constructors and against the object parameter of the conversion functions. \end{note} @@ -1015,7 +1046,7 @@ The argument list has one argument, which is the initializer expression. \begin{note} This argument will be compared against -the implicit object parameter of the conversion functions. +the object parameter of the conversion functions. \end{note} \rSec3[over.match.ref]{Initialization by conversion function for direct reference binding}% @@ -1058,7 +1089,7 @@ The argument list has one argument, which is the initializer expression. \begin{note} This argument will be compared against -the implicit object parameter of the conversion functions. +the object parameter of the conversion functions. \end{note} \rSec3[over.match.list]{Initialization by list-initialization}% @@ -1860,7 +1891,7 @@ However, if the target is \begin{itemize} \item the first parameter of a constructor or -\item the implicit object parameter of a user-defined conversion function +\item the object parameter of a user-defined conversion function \end{itemize} and the constructor or user-defined conversion function is a candidate by \begin{itemize} @@ -1937,6 +1968,10 @@ In all contexts, when converting to the implicit object parameter or when converting to the left operand of an assignment operation only standard conversion sequences are allowed. +\begin{note} +When converting to the explicit object parameter, if any, +user-defined conversion sequences are allowed. +\end{note} \pnum If no conversions are required to match an argument to a @@ -2066,7 +2101,7 @@ conversion is specified by a conversion function\iref{class.conv.fct}, the initial standard conversion sequence converts the source type to the type of the -implicit object parameter of that conversion function. +object parameter of that conversion function. \pnum The second standard conversion sequence converts the result of @@ -2837,14 +2872,16 @@ is added to the set of selected functions considered. \pnum -Non-member functions and static member functions +Non-member functions, +static member functions, and +explicit object member functions match targets of function pointer type or reference to function type. Non-static member functions match targets of pointer-to-member-function type. \begin{note} %% FIXME: Should this only apply after the eliminations in the next paragraph? -If a non-static member function is chosen, +If an implicit object member function is chosen, the result can be used only to form a pointer to member\iref{expr.unary.op}. \end{note} @@ -3046,7 +3083,7 @@ \indextext{restriction!overloading}% An operator function shall either be a non-static member function or be a non-member function that -has at least one parameter whose type is a class, a reference to a class, an +has at least one non-object parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration. It is not possible to change the precedence, grouping, or number of operands of operators. @@ -3104,7 +3141,7 @@ is a function named \tcode{\keyword{operator}@} for a prefix \grammarterm{unary-operator} \tcode{@}\iref{expr.unary.op} that is either -a non-static member function\iref{class.mfct} with no parameters or +a non-static member function\iref{class.mfct} with no non-object parameters or a non-member function with one parameter. \indextext{unary operator!interpretation of}% For a \grammarterm{unary-expression} @@ -3142,7 +3179,7 @@ A \defnadj{binary}{operator function} is a function named \tcode{\keyword{operator}@} for a binary operator \tcode{@} that is either -a non-static member function\iref{class.mfct} with one parameter or +a non-static member function\iref{class.mfct} with one non-object parameter or a non-member function with two parameters. \indextext{binary operator!interpretation of}% For an expression \tcode{$x$ @ $y$} with subexpressions $x$ and $y$, @@ -3260,7 +3297,7 @@ \pnum A \defnadj{subscripting}{operator function} is a function named \tcode{\keyword{operator}[]} -that is a non-static member function with exactly one parameter. +that is a non-static member function with exactly one non-object parameter. For an expression of the form \begin{ncsimplebnf} postfix-expression \terminal{[} expr-or-braced-init-list \terminal{]} @@ -3293,7 +3330,7 @@ \pnum A \defnadj{class member access}{operator function} is a function named \tcode{\keyword{operator}->} -that is a non-static member function taking no parameters. +that is a non-static member function taking no non-object parameters. For an expression of the form \begin{ncsimplebnf} postfix-expression \terminal{->} \opt{\keyword{template}} id-expression @@ -3314,12 +3351,12 @@ \pnum An \defnadj{increment}{operator function} is a function named \tcode{\keyword{operator}++}. -If this function is a non-static member function with no parameters, or a non-member +If this function is a non-static member function with no non-object parameters, or a non-member function with one parameter, it defines the prefix increment operator \tcode{++} for objects of that type. -If the function is a non-static member function with one parameter (which shall be of type +If the function is a non-static member function with one non-object parameter (which shall be of type \tcode{int}) or a non-member function with two parameters (the second of which shall be of type \tcode{int}), diff --git a/source/preprocessor.tex b/source/preprocessor.tex index c432c17659..a50ec234ba 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -1776,6 +1776,7 @@ \defnxname{cpp_delegating_constructors} & \tcode{200604L} \\ \rowsep \defnxname{cpp_designated_initializers} & \tcode{201707L} \\ \rowsep \defnxname{cpp_enumerator_attributes} & \tcode{201411L} \\ \rowsep +\defnxname{cpp_explicit_this_parameter} & \tcode{202110L} \\ \rowsep \defnxname{cpp_fold_expressions} & \tcode{201603L} \\ \rowsep \defnxname{cpp_generic_lambdas} & \tcode{201707L} \\ \rowsep \defnxname{cpp_guaranteed_copy_elision} & \tcode{201606L} \\ \rowsep diff --git a/source/templates.tex b/source/templates.tex index d93b41930c..880f54c5d7 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -5059,6 +5059,11 @@ a structured binding declaration\iref{dcl.struct.bind} whose \grammarterm{brace-or-equal-initializer} is type-dependent, \item +associated by name lookup with +an entity captured by copy\iref{expr.prim.lambda.capture} +in a \grammarterm{lambda-expression} +that has an explicit object parameter whose type is dependent\iref{dcl.fct}, +\item the \grammarterm{identifier} \mname{func}\iref{dcl.fct.def.general}, where any enclosing function is a