From 2c32eff71e20c3019dba069c4789506d47c4a21b Mon Sep 17 00:00:00 2001 From: Sudrut Date: Mon, 15 Dec 2025 22:18:10 +0800 Subject: [PATCH 01/10] feat: add `_meta.yml` for `cpp/language/functions` --- src/content/docs/cpp/language/functions/_meta.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/content/docs/cpp/language/functions/_meta.yml diff --git a/src/content/docs/cpp/language/functions/_meta.yml b/src/content/docs/cpp/language/functions/_meta.yml new file mode 100644 index 0000000..09d8dd6 --- /dev/null +++ b/src/content/docs/cpp/language/functions/_meta.yml @@ -0,0 +1 @@ +label: Functions \ No newline at end of file From a4f3baaead324cf9820b379940ab476d3a9a0517 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Mon, 15 Dec 2025 22:47:25 +0800 Subject: [PATCH 02/10] feat: migrate `cpp/language/functions` --- src/content/docs/cpp/language/functions.mdx | 58 +++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/content/docs/cpp/language/functions.mdx diff --git a/src/content/docs/cpp/language/functions.mdx b/src/content/docs/cpp/language/functions.mdx new file mode 100644 index 0000000..543445d --- /dev/null +++ b/src/content/docs/cpp/language/functions.mdx @@ -0,0 +1,58 @@ +--- +title: Overview +sidebar: + order: 1 +cppdoc: + keys: ["cpp.lang.functions"] +--- + +import { Revision, RevisionBlock } from "@components/revision"; +import DocLink from "@components/DocLink.astro"; +import NamedReq from "@components/NamedReq.astro"; + +Functions are C++ entities that associate a sequence of statements (a _function body_) with a _name_ and a list of zero or more _function parameters_. + +```cpp +// function name: "isodd" +// parameter list has one parameter, with name "n" and type int +// the return type is bool +bool isodd(int n) { // the body of the function begins + return n % 2; +} // the body of the function ends +``` + +When a function is invoked, e.g. in a function-call expression, the parameters are initialized from the arguments (either provided at the place of call or defaulted) and the statements in the function body are executed. If the parameter list ends with `...`, extra arguments can be supplied to the function, such a function is called variadic function. + +```cpp +int main() { + for (int arg : {-3, -2, -1, 0, 1, 2, 3}) + std::cout << isodd(arg) << ' '; // isodd called 7 times, each + // time n is copy-initialized from arg +} +``` + +Unqualified function names in function-call expressions are looked up with an extra set of rules called "argument-dependent lookup" (ADL). + +A function can terminate by returning or by throwing an exception. + + + A function may be a coroutine, in which case it can suspend execution to be resumed later. + + +A function declaration may appear in any scope, but a function definition may only appear in namespace scope or, for member and friend functions, in class scope. A function that is declared in a class body without a friend specifier is a class member function. Such functions have many additional properties, see member functions for details. + +Functions are not objects: there are no arrays of functions and functions cannot be passed by value or returned from other functions. Pointers and references to functions (except for the main function and most standard library functions) are allowed, and may be used where these functions themselves cannot. Therefore we say these functions are "addressable". + +Each function has a type, which consists of the function's return type, the types of all parameters (after array-to-pointer and function-to-pointer transformations, see parameter list) , whether the function is noexcept or not, and, for non-static member functions, cv-qualification and ref-qualification. Function types also have language linkage. There are no cv-qualified function types (not to be confused with the types of cv-qualified functions such as `int f() const;` or functions returning cv-qualified types, such as `std::string const f();`). Any cv-qualifier is ignored if it is added to an alias for a function type. + +Multiple functions in the same scope may have the same name, as long as their parameter lists and, for non-static member functions, cv/ref-qualifications are different. This is known as function overloading. Function declarations that differ only in the return type and the noexcept specification cannot be overloaded. The address of an overloaded function is determined differently. + + + C++ implements [anonymous functions](https://en.wikipedia.org/wiki/anonymous_function) using lambda-expressions. + + +## Function objects + +Besides function lvalues, the function call expression supports pointers to functions, and any value of class type that overloads the function-call operator or is convertible to function pointer( including lambda-expressions). Together, these types are known as , and they are used ubiquitously through the C++ standard library, see for example, usages of and . + +The standard library also provides a number of predefined function object templates as well as the methods to compose new ones (including `std::less`, `std::mem_fn`, `std::bind`, `std::function`, `std::not_fn`, `std::bind_front`, `std::bind_back`, `std::move_only_function`, `std::copyable_function`, and `std::function_ref`). \ No newline at end of file From ac877e0a2a429d6fa10ed5ce71752f80dba60e89 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 00:09:09 +0800 Subject: [PATCH 03/10] feat: migrate `cpp/language/functions/function` --- .../docs/cpp/language/functions/function.mdx | 1470 +++++++++++++++++ 1 file changed, 1470 insertions(+) create mode 100644 src/content/docs/cpp/language/functions/function.mdx diff --git a/src/content/docs/cpp/language/functions/function.mdx b/src/content/docs/cpp/language/functions/function.mdx new file mode 100644 index 0000000..eefdf64 --- /dev/null +++ b/src/content/docs/cpp/language/functions/function.mdx @@ -0,0 +1,1470 @@ +--- +title: Function declaration +sidebar: + order: 2 +cppdoc: + keys: ["cpp.lang.functions.function"] +--- + +import { Decl, DeclDoc } from "@components/decl-doc"; +import { DR, DRList } from "@components/defect-report"; +import { + FeatureTestMacro, + FeatureTestMacroValue, +} from "@components/feature-test-macro"; +import { Desc, DescList, DocLink } from '@components/index'; +import { ParamDoc, ParamDocList } from "@components/param-doc"; +import { autoRev, Revision, RevisionBlock } from "@components/revision"; +import Behavior from "@components/Behavior.astro"; + +A function declaration introduces the function name and its type. A function definition associates the function name/type with the function body. + +## Function declaration + +Function declarations may appear in any scope. A function declaration at class scope introduces a class member function (unless the `friend` specifier is used), see member functions and friend functions for details. + + + + + ```cpp cxx-mark + /*$s:noptr-declarator*/ ( /*$s:parameter-list*/ ) + /*$s:cv*//*$opt*/ + /*$s:except*//*$opt*/ + ``` + + + + + ```cpp cxx-mark + /*$s:noptr-declarator*/ ( /*$s:parameter-list*/ ) + /*$s:cv*//*$opt*/ + /*$s:ref*//*$opt*/ + /*$s:except*//*$opt*/ + /*$s:attr*//*$opt*/ + ``` + + + + Regular function declarator syntax. + + + + + + ```cpp cxx-mark + /*$s:noptr-declarator*/ ( /*$s:parameter-list*/ ) + /*$s:cv*//*$opt*/ + /*$s:ref*//*$opt*/ + /*$s:except*//*$opt*/ + /*$s:attr*//*$opt*/ + -> /*$s:trailing*/ + ``` + + + + Trailing return type declaration. The `decl-specifier-seq` in this case must contain the keyword `auto`. + + +(see Declarations for the other forms of the `declarator` syntax) + + + + any valid `declarator`, but if it begins with `*`, `&`, or `&&`, it has to be surrounded by parentheses. + + + possibly empty, comma-separated list of the function parameters (see below for details) + + + const/volatile qualification, only allowed in non-static member function declarations + + + + dynamic exception specification + + + either dynamic exception specification or noexcept specification + + + noexcept specification + + + + + + + + a list of attributes. These attributes are applied to the type of the function, not the function itself. The attributes for the function appear after the identifier within the declarator and are combined with the attributes that appear in the beginning of the declaration, if any. + + + const/volatile qualification, only allowed in non-static member function declarations + + + Trailing return type, useful if the return type depends on argument names, such as `template auto add(T t, U u) -> decltype(t + u);` or is complicated, such as in `auto fpif(int)->int(*)(int)` + + + + + + As mentioned in Declarations, the declarator can be followed by a requires clause, which declares the associated constraints for the function, which must be satisfied in order for the function to be selected by overload resolution. (example: `void f1(int a) requires true;`) Note that the associated constraint is part of function signature, but not part of function type. + + +Function declarators can be mixed with other declarators, where the declaration specifier sequence allows: + +```cpp +// declares an int, an int*, a function, and a pointer to a function +int a = 1, *p = NULL, f(), (*pf)(double); +// decl-specifier-seq is int +// declarator f() declares (but doesn't define) +// a function taking no arguments and returning int + +struct S { + virtual int f(char) const, g(int) &&; // declares two non-static member functions + virtual int f(char), x; // compile-time error: virtual (in decl-specifier-seq) + // is only allowed in declarations of non-static + // member functions +}; +``` + + + Using a volatile-qualified object type as parameter type or return type is deprecated. + + +The return type of a function cannot be a function type or an array type (but can be a pointer or reference to those). + + + As with any declaration, attributes that appear before the declaration and the attributes that appear immediately after the identifier within the declarator both apply to the entity being declared or defined (in this case, to the function): + + ```cpp + [[noreturn]] void f [[noreturn]] (); // OK: both attributes apply to the function f + ``` + + However, the attributes that appear after the declarator (in the syntax above), apply to the type of the function, not to the function itself: + + ```cpp + void f() [[noreturn]]; // Error: this attribute has no effect on the function itself + ``` + + +
+ ## Return type deduction :badge[C++14] + + f the `decl-specifier-seq` of the function declaration contains the keyword `auto`, trailing return type may be omitted, and will be deduced by the compiler from the type of the operand used in the non-discarded return statement. If the return type does not use `decltype(auto)`, the deduction follows the rules of template argument deduction: + + ```cpp + int x = 1; + auto f() { return x; } // return type is int + const auto& f() { return x; } // return type is const int& + ``` + + If the return type is `decltype(auto)`, the return type is as what would be obtained if the operand used in the return statement were wrapped in decltype: + + ```cpp + int x = 1; + decltype(auto) f() { return x; } // return type is int, same as decltype(x) + decltype(auto) f() { return(x); } // return type is int&, same as decltype((x)) + ``` + + (note: `const decltype(auto)&` is an error, `decltype(auto)` must be used on its own) + + If there are multiple return statements, they must all deduce to the same type: + + ```cpp + auto f(bool val) { + if (val) return 123; // deduces return type int + else return 3.14f; // Error: deduces return type float + } + ``` + + If there is no return statement or if the operand of the return statement is a void expression (including return statements with no operand), the declared return type must be either `decltype(auto)`, in which case the deduced return type is `void`, or (possibly cv-qualified) `auto`, in which case the deduced return type is then (identically cv-qualified) `void`: + + ```cpp + auto f() {} // returns void + auto g() { return f(); } // returns void + auto* x() {} // Error: cannot deduce auto* from void + ``` + + Once a return statement has been seen in a function, the return type deduced from that statement can be used in the rest of the function, including in other return statements: + + ```cpp + auto sum(int i) { + if (i == 1) + return i; // sum’s return type is int + else + return sum(i - 1) + i; // OK: sum’s return type is already known + } + ``` + + If the return statement uses a brace-enclosed initializer list, deduction is not allowed: + + ```cpp + auto func() { return {1, 2, 3}; } // Error + ``` + + Virtual functions and coroutines cannot use return type deduction: + + ```cpp + struct F { + virtual auto f() { return 2; } // Error + }; + ``` + + Function templates other than user-defined conversion functions can use return type deduction. The deduction takes place at instantiation even if the expression in the return statement is not dependent. This instantiation is not in an immediate context for the purposes of SFINAE. + + ```cpp + template + auto f(T t) { return t; } + typedef decltype(f(1)) fint_t; // instantiates f to deduce return type + + template + auto f(T* t) { return *t; } + void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types, + // chooses second template overload + ``` + + Redeclarations or specializations of functions or function templates that use return type deduction must use the same return type placeholders: + + ```cpp + auto f(int num) { return num; } + // int f(int num); // Error: no placeholder return type + // decltype(auto) f(int num); // Error: different placeholder + + template + auto g(T t) { return t; } + template auto g(int); // OK: return type is int + // template char g(char); // Error: not a specialization of the primary template g + ``` + + Similarly, redeclarations or specializations of functions or function templates that do not use return type deduction must not use a placeholder: + + ```cpp + int f(int num); + // auto f(int num) { return num; } // Error: not a redeclaration of f + + template + T g(T t) { return t; } + template int g(int); // OK: specialize T as int + // template auto g(char); // Error: not a specialization of the primary template g + ``` + + Explicit instantiation declarations do not themselves instantiate function templates that use return type deduction: + + ```cpp + template + auto f(T t) { return t; } + extern template auto f(int); // does not instantiate f + + int (*p)(int) = f; // instantiates f to determine its return type, + // but an explicit instantiation definition + // is still required somewhere in the program + ``` +
+ +## Parameter List + +The parameter list determines the arguments that can be specified when the function is called. It is a comma-separated list of _parameter declarations_, each of which has the following syntax: + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + ``` + + + + Declares a named (formal) parameter. For the meanings of `decl-specifier-seq` and `declarator`, see declarations. + + ```cpp + int f(int a, int* p, int (*(*x)(double))[3]); + ``` + + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + this /*$s:decl-specifier-seq*/ /*$s:declarator*/ + ``` + + + + Declares a named [explicit object parameter](#explicit-object-parameter). + + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + = /*$s:initializer*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + = /*$s:initializer*/ + ``` + + + + Declares a named (formal) parameter with a default value. + + ```cpp + int f(int a = 7, int* p = nullptr, int (*(*x)(double))[3] = nullptr); + ``` + + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + ``` + + + + Declares an unnamed parameter. + + ```cpp + int f(int, int*, int (*(*)(double))[3]); + ``` + + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + this /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + ``` + + + + Declares an unnamed [explicit object parameter](#explicit-object-parameter). + + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + = /*$s:initializer*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + = /*$s:initializer*/ + ``` + + + + Declares an unnamed parameter with a default value. + + ```cpp + int f(int = 7, int* = nullptr, int (*(*)(double))[3] = nullptr); + ``` + + + + + ```cpp + void + ``` + + + Indicates that the function takes no parameters, it is the exact synonym for an empty parameter list: `int f(void);` and `int f();` declare the same function. + + `void` is the only syntax equivalent to an empty parameter list, other usages of `void` parameters are ill-formed: + + + + + + + + + + + + + + + + + + + + + + + + + + +
**Incorrect usage****Example**
multiple parameters are present`int f1(void, int);`
the `void` parameter is named`inf f2(void param);`
`void` is cv-qualified`int f3(const void);`
`void` is dependent`int f4(T);` (where `T` is `void`)
+ + the `void` parameter is an [explicit object parameter](#explicit-object-parameter) + + `int f5(this void);`
+
+ + + Although `decl-specifier-seq` implies there can exist specifiers other than type specifiers, the only other specifier allowed is `register` as well as `auto`, and it has no effect. + + + + If any of the function parameters uses a placeholder (either `auto` or a concept type), the function declaration is instead an abbreviated function template declaration: + + ```cpp + void f1(auto); // same as template void f1(T) + void f2(C1 auto); // same as template void f2(T), if C1 is a concept + ``` + + + + + + A parameter declaration with the specifier `this` (syntax (2)/(5)) declares an _explicit object parameter_. + + An explicit object parameter cannot be a function parameter pack, and it can only appear as the first parameter of the parameter list in the following declarations: + + - a declaration of a member function or member function template + - an explicit instantiation or explicit specialization of a templated member function + - a lambda declaration + + A member function with an explicit object parameter has the following restrictions: + + - The function is not static. + - The function is not virtual. + - The declarator of the function does not contain `cv` and `ref`. + + ```cpp + struct C { + void f(this C& self); // OK + + template + void g(this Self&& self); // also OK for templates + + void p(this C) const; // Error: “const” not allowed here + static void q(this C); // Error: “static” not allowed here + void r(int, this C); // Error: an explicit object parameter + // can only be the first parameter + }; + + // void func(this C& self); // Error: non-member functions cannot have + // an explicit object parameter + ``` + + +Parameter names declared in function declarations are usually for only self-documenting purposes. They are used (but remain optional) in function definitions. + +An ambiguity arises in a parameter list when a type name is nested in parentheses (including lambda expressions). In this case, the choice is between the declaration of a parameter of type pointer to function and the declaration of a parameter with redundant parentheses around the identifier of the `declarator`. The resolution is to consider the type name as a simple type specifier (which is the pointer to function type): + +```cpp +class C {}; + +void f(int(C)) {} // void f(int(*fp)(C param)) {} + // NOT void f(int C) {} + +void g(int *(C[10])); // void g(int *(*fp)(C param[10])); + // NOT void g(int *C[10]); +``` + +Parameter type cannot be a type that includes a reference or a pointer to array of unknown bound, including a multi-level pointers/arrays of such types, or a pointer to functions whose parameters are such types. + +### Using an ellipsis + +The last parameter in the parameter list can be an ellipsis (`...`); this declares a variadic function. The comma preceding the ellipsis can be omitted: + +```cpp +int printf(const char* fmt, ...); // a variadic function +int printf(const char* fmt...); // same as above, but deprecated since C++26 + +template +void f(Args..., ...); // a variadic function template with a parameter pack + +template +void f(Args... ...); // same as above, but deprecated since C++26 + +template +void f(Args......); // same as above, but deprecated since C++26 +``` + +## Function type + +### Parameter-type-list + +A function’s _parameter-type-list_ is determined as follows: + +1. The type of each parameter (including function parameter packs) is determined from its own [parameter declaration](#parameter-list). +2. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. +3. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. +4. The resulting list of transformed parameter types and the presence or absence of the [ellipsis](#using-an-ellipsis) or a function parameter pack is the function’s parameter-type-list. + +```cpp +void f(char*); // #1 +void f(char[]) {} // defines #1 +void f(const char*) {} // OK, another overload +void f(char* const) {} // Error: redefines #1 + +void g(char(*)[2]); // #2 +void g(char[3][2]) {} // defines #2 +void g(char[3][3]) {} // OK, another overload + +void h(int x(const int)); // #3 +void h(int (*)(int)) {} // defines #3 +``` + +### Determining function type + +In syntax (1), assuming `noptr-declarator` as a standalone declaration, given the type of the `qualified-id` or `unqualified-id` in `noptr-declarator` as “derived-declarator-type-list T”: + + + - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning T”. + + +- TheOtherwise, the type of the function declared is “derived-declarator-type-list function of parameter-type-list `cv` (optional) `ref` (optional) returning T”. + + + In syntax (2), assuming `noptr-declarator` as a standalone declaration, given the type of the `qualified-id` or `unqualified-id` in `noptr-declarator` as “derived-declarator-type-list T” (T must be `auto` in this case): + + + + - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning `trailing`”. + + + + - TheOtherwise, the type of the function declared is “derived-declarator-type-list function of parameter-type-list `cv` (optional) `ref` (optional) returning `trailing`”. + + `attr`, if present, applies to the function type. + + +```cpp +// the type of “f1” is +// “function of int returning void, with attribute noreturn” +void f1(int a) [[noreturn]]; + +// the type of “f2” is +// “constexpr noexcept function of pointer to int returning int” +constexpr auto f2(int[] b) noexcept -> int; + +struct X { + // the type of “f3” is + // “function of no parameter const returning const int” + const int f3() const; +}; +``` + +### Trailing qualifiers + +A function type with `cv` or `ref` (including a type named by typedef name) can appear only as: + +- the function type for a non-static member function, +- the function type to which a pointer to member refers, +- the top-level function type of a function `typedef` declaration or alias declaration, +- the type-id in the default argument of a template type parameter, or +- the type-id of a template argument for a template type parameter. + +```cpp +typedef int FIC(int) const; +FIC f; // Error: does not declare a member function + +struct S { + FIC f; // OK +}; + +FIC S::*pm = &S::f; // OK +``` + +## Function signature + +Every function has a signature. + +The signature of a function consists of its name and [parameter-type-list](#parameter-type-list). Its signature also contains the enclosing namespace, with the following exceptions: + +- If the function is a member function, its signature contains the class of which the function is a member instead of the enclosing namespace. Its signature also contains the following components, if exists: + - `cv` + + - `ref` + + + - trailing requires clause + + + + - If the function is a non-template friend function with a trailing requires clause, its signature contains the enclosing class instead of the enclosing namespace. The signature also contains the trailing requires clause. + + +`except` and `attr` doesn't involve function signature, although noexcept specification affects the function type. + +## Function definition + +A non-member function definition may appear at namespace scope only (there are no nested functions). A member function definition may also appear in the body of a class definition. They have the following syntax: + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*//*$opt*/ + /*$s:declarator*/ + /*$s:function-body*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*//*$opt*/ + /*$s:declarator*/ + /*$s:virt-specs*//*$opt*/ + /*$s:function-body*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*//*$opt*/ + /*$s:declarator*/ + /*$s:virt-specs*//*$opt*/ + /*$s:contract-specs*//*$opt*/ + /*$s:function-body*/ + ``` + + + + A function definition without constraints. + + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*//*$opt*/ + /*$s:declarator*/ + /*$s:require-clause*/ + /*$s:function-body*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*//*$opt*/ + /*$s:declarator*/ + /*$s:require-clause*/ + /*$s:contract-specs*//*$opt*/ + /*$s:function-body*/ + ``` + + + + A function definition with constraints. + + + + + the return type with specifiers, as in the declaration grammar + + + function declarator, same as in the function declaration grammar above (can be parenthesized) + + + the function body (see below) + + + + + + + a list of attributes. These attributes are combined with the attributes after the identifier in the `declarator` (see top of this page), if any. + + + override, final, or their combination in any order + + + + + + + + a requires clause + + + + + + + + a list of [function contract specifiers](#function-contract-specifiers) + + + + +`function-body` is one of the following: + + + + ```cpp cxx-mark + /*$s:ctor-initializer*//*$opt*/ /*$s:compound-statement*/ + ``` + + + Regular function body. + + + + + ```cpp cxx-mark + /*$s:function-try-block*/ + ``` + + + Function try block. + + + + + + ```cpp + = default ; + ``` + + + + Explicitly defaulted function definition. + + + + + + ```cpp + = delete ; + ``` + + + + Explicitly deleted function definition. + + + + + + ```cpp cxx-mark + = delete ( /*$s:string-literal*/ ); + ``` + + + + Explicitly deleted function definition with error message. + + + + + member initializer list, only allowed in constructors + + + the brace-enclosed sequence of statements that constitutes the body of a function + + + a function try block + + + + + + + an unevaluated string literal that could be used to explain the rationale for why the function is deleted + + + + +```cpp +int max(int a, int b, int c) { + int m = (a > b) ? a : b; + return (m > c) ? m : c; +} + +// decl-specifier-seq is “int” +// declarator is “max(int a, int b, int c)” +// body is { ... } +``` + +The function body is a compound statement (sequence of zero or more statements surrounded by a pair of curly braces), which is executed when the function call is made. Moreover, the function body of a constructor also includes the following: + +- For all non-static data members whose identifiers are absent in the constructor's member initializer list, the default member initializers or default-initializations used to initialize the corresponding member subobjects. +- For all base classes whose type names are absent in the constructor's member initializer list, the default-initializations used to initialize the corresponding base class subobjects. + + + If a function definition contains a `virt-specs`, it must define a member function. + + ```cpp + void f() override {} // Error: not a member function + ``` + + + + If a function definition contains a `requires-clause`, it must define a templated function. + + ```cpp + void g() requires (sizeof(int) == 4) {} // Error: not a templated function + ``` + + +The parameter types, as well as the return type of a function definition cannot be (possibly cv-qualified) incomplete class types unless the function is defined as deleted. The completeness check is only made in the function body, which allows member functions to return the class in which they are defined (or its enclosing class), even if it is incomplete at the point of definition (it is complete in the function body). + +The parameters declared in the `declarator` of a function definition are in scope within the body. If a parameter is not used in the function body, it does not need to be named (it's sufficient to use an abstract declarator): + +```cpp +void print(int a, int) // second parameter is not used +{ + std::printf("a = %d\n", a); +} +``` + +Even though top-level cv-qualifiers on the parameters are discarded in function declarations, they modify the type of the parameter as visible in the body of a function: + +```cpp +void f(const int n) // declares function of type void(int) +{ + // but in the body, the type of “n” is const int +} +``` + +
+ ### Defaulted functions :badge[C++11] + + If `function-body` is of syntax (3), the function is defined as _explicitly defaulted_. + + A function that is explicitly defaulted must be a special member function or comparison operator function, and it must have no default argument. + + An explicitly defaulted special member function F1 is allowed to differ from the corresponding special member function F2 that would have been implicitly declared, as follows: + + - F1 and F2 may have different `ref` and/or `except`. + - If F2 has a non-object parameter of type `const C&`, the corresponding non-object parameter of F1 maybe of type `C&`. + + + - If F2 has an implicit object parameter of type “reference to C”, F1 may be an explicit object member function whose [explicit object parameter](#explicit-object-parameter) is of (possibly different) type “reference to C”, in which case the type of F1 would differ from the type of F2 in that the type of F1 has an additional parameter. + + + If the type of F1 differs from the type of F2 in a way other than as allowed by the preceding rules, then: + + - If F1 is an assignment operator, and the return type of F1 differs from the return type of F2 or F1’s non-object parameter type is not a reference, the program is ill-formed. + - Otherwise, if F1 is explicitly defaulted on its first declaration, it is defined as deleted. + - Otherwise, the program is ill-formed. + + A function explicitly defaulted on its first declaration is implicitly inline, and is implicitly constexpr if it can be a constexpr function. + + ```cpp + struct S { + S(int a = 0) = default; // error: default argument + void operator=(const S&) = default; // error: non-matching return type + ~S() noexcept(false) = default; // OK, different exception specification + private: + int i; + S(S&); // OK, private copy constructor + }; + + S::S(S&) = default; // OK, defines copy constructor + ``` + + Explicitly-defaulted functions and implicitly-declared functions are collectively called _defaulted_ functions. Their actual definitions will be implicitly provided, see their corresponding pages for details. + + ### Deleted functions :badge[C++11] + + If `function-body` is of syntax (4) or (5), the function is defined as _explicitly deleted_. + + Any use of a deleted function is ill-formed (the program will not compile). This includes calls, both explicit (with a function call operator) and implicit (a call to deleted overloaded operator, special member function, allocation function, etc), constructing a pointer or pointer-to-member to a deleted function, and even the use of a deleted function in an expression that is not potentially-evaluated. + + A non-pure virtual member function can be defined as deleted, even though it is implicitly odr-used. A deleted function can only be overridden by deleted functions, and a non-deleted function can only be overridden by non-deleted functions. + + + If `string-literal` is present, the implementation is encouraged to include the text of it as part of the resulting diagnostic message which shows the rationale for deletion or to suggest an alternative. + + + If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected: + + ```cpp + struct T { + void* operator new(std::size_t) = delete; + void* operator new[](std::size_t) = delete("new[] is deleted"); // since C++26 + }; + + T* p = new T; // Error: attempts to call deleted T::operator new + T* p = new T[5]; // Error: attempts to call deleted T::operator new[], + // emits a diagnostic message “new[] is deleted” + ``` + + The deleted definition of a function must be the first declaration in a translation unit: a previously-declared function cannot be redeclared as deleted: + + ```cpp + struct T { T(); }; + T::T() = delete; // Error: must be deleted on the first declaration + ``` + + ### User-provided functions :badge[C++11] + + A function is _user-provided_ if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base. + + ```cpp + // All special member functions of “trivial” are + // defaulted on their first declarations respectively, + // they are not user-provided + struct trivial { + trivial() = default; + trivial(const trivial&) = default; + trivial(trivial&&) = default; + trivial& operator=(const trivial&) = default; + trivial& operator=(trivial&&) = default; + ~trivial() = default; + }; + + struct nontrivial { + nontrivial(); // first declaration + }; + + // not defaulted on the first declaration, + // it is user-provided and is defined here + nontrivial::nontrivial() = default; + ``` + + ### Ambiguity Resolution :badge[C++11] + + In the case of an ambiguity between a function body and an initializer beginning with `{` or `=`, the ambiguity is resolved by checking the type of the declarator identifier of `noptr-declarator`: + + - If the type is a function type, the ambiguous token sequence is treated as a function body. + - Otherwise, the ambiguous token sequence is treated as an initializer. + + ```cpp + using T = void(); // function type + using U = int; // non-function type + + T a{}; // defines a function doing nothing + U b{}; // value-initializes an int object + + T c = delete("hello"); // defines a function as deleted + U d = delete("hello"); // copy-initializes an int object with + // the result of a delete expression (ill-formed) + ``` + + ### \_\_func\_\_ :badge[C++11] + + Within the function body, the function-local predefined variable `__func__` is defined as if by + + ```cpp + static const char __func__[] = "function-name"; + ``` + + This variable has block scope and static storage duration: + + ```cpp + struct S { + S(): s(__func__) {} // OK: initializer-list is part of function body + const char* s; + }; + void f(const char* s = __func__); // Error: parameter-list is part of declarator + ``` + + ```cpp + #include + + void Foo() { std::cout << __func__ << ' '; } + + struct Bar { + Bar() { std::cout << __func__ << ' '; } + ~Bar() { std::cout << __func__ << ' '; } + struct Pub { Pub() { std::cout << __func__ << ' '; } }; + }; + + int main() { + Foo(); + Bar bar; + Bar::Pub pub; + } + ``` + + Possible output: + + ``` + Foo Bar Pub ~Bar + ``` +
+ +
+ ## Function contract specifiers :badge[C++26] + + Function declarations and lambda expressions can contain a sequence of _function contract specifiers_, each specifier has the following syntax: + + + + ```cpp + pre /* attr (optional) */ (/* predicate */) + ``` + + + Introduces a _precondition assertion_. + + + + + ```cpp + post /* attr (optional) */ (/* predicate */) + ``` + + + Introduces a _postcondition assertion_ in which the assertion does not bind to the result. + + + + + ```cpp + post /* attr (optional) */ (/* identifier */ /* result-attr (optional) */ : /* predicate */) + ``` + + + Introduces a _postcondition assertion_ in which the assertion binds to the result. + + + + + a list of attributes appertaining to the introduced contract assertion + + + any expression (except unparenthesized comma expressions) + + + the identifier that refers to the result + + + a list of attributes appertaining to the result binding + + + + Precondition assertion and postcondition assertion are collectively called _function contract assertion_. + + A function contract assertion is a contract assertion associated with a function. The predicate of a function contract assertion is its `predicate` contextually converted to `bool`. + + The following functions cannot be declared with function contract specifiers: + + - virtual functions + - [deleted functions](#deleted-functions) + - function [defaulted](#defaulted-functions) on their first declarations + + ### Precondition assertions + + A precondition assertion is associated with entering a function: + + ```cpp + int divide(int dividend, int divisor) pre(divisor != 0) { + return dividend / divisor; + } + + double square_root(double num) pre(num >= 0) { + return std::sqrt(num); + } + ``` + + ### Postcondition assertions + + A postcondition assertion is associated with exiting a function normally. + + If a postcondition assertion has an `identifier`, the function contract specifier introduces `identifier` as the name of a _result binding_ of the associated function. A result binding denotes the object or reference returned by invocation of that function. The type of a result binding is the return type of its associated function. + + ```cpp + int absolute_value(int num) post(r : r >= 0) { + return std::abs(num); + } + + double sine(double num) post(r : r >= -1.0 && r <= 1.0) { + if (std::isnan(num) || std::isinf(num)) + // exiting via an exception never causes contract violation + throw std::invalid_argument("Invalid argument"); + return std::sin(num); + } + ``` + + If a postcondition assertion has an `identifier`, and the return type of the associated function is (possibly cv-qualified) `void`, the program is ill-formed: + + ```cpp + void f() post(r : r > 0); // Error: no value can be bound to “r” + ``` + + When the declared return type of a non-templated function contains a placeholder type, a postcondition assertion with an `identifier` can only appear in a function definition: + + ```cpp + auto g(auto&) post(r : r >= 0); // OK, “g” is a template + + auto h() post(r : r >= 0); // Error: cannot name the return value + + auto k() post(r : r >= 0) // OK, “k” is a definition + { + return 0; + } + ``` + + ### Contract consistency + + A redeclaration D of a function or function template `func` must have either no `contract-specs` or the same contract-specs as any first declaration F reachable from D. If D and F are in different translation units, a diagnostic is required only if D is attached to a named module. + + If a declaration F1 is a first declaration of func in one translation unit and a declaration F2 is a first declaration of `func` in another translation unit, F1 and F2 must specify the same `contract-specs`, no diagnostic required. + + Two `contract-specs`s are the same if they consist of the same function contract specifiers in the same order. + + A function contract specifier C1 on a function declaration D1 is the same as a function contract specifier C2 on a function declaration D2 if all following conditions are satisfied: + + - The `predicate`s of C1 and C2 would satisfy the one-definition rule if placed in function definitions on the declarations D1 and D2 (if D1 and D2 are in different translation units, corresponding entities defined within each `predicate` behave as if there is a single entity with a single definition), respectively, except for the following renamings: + - The renaming of the parameters of the declared function. + - The renaming of template parameters of a template enclosing the declared function. + - The renaming of the result binding (if any). + - Both C1 and C2 have an `identifier` or neither have. + + If this condition is not met solely due to the comparison of two lambda expressions that are contained within the `predicate`s, no diagnostic is required. + + ```cpp + bool b1, b2; + + void f() pre (b1) pre([]{ return b2; }()); + void f(); // OK, function contract specifiers omitted + void f() pre (b1) pre([]{ return b2; }()); // Error: closures have different types + void f() pre (b1); // Error: function contract specifiers are different + + int g() post(r : b1); + int g() post(b1); // Error: no result binding + + namespace N { + void h() pre (b1); + bool b1; + void h() pre (b1); // Error: function contract specifiers differ + // according to the one−definition rule + } + ``` +
+ +## Notes + +In case of ambiguity between a variable declaration using the direct-initialization syntax and a function declaration, the compiler always chooses function declaration; see direct-initialization. + + + + decltype(auto) + + + + + + [return type deduction](#return-type-deduction) for normal functions + + + + + + [explicit object parameters](#explicit-object-parameter) (deducing this) + + + + + + deleted function with a reason + + + +## Keywords + +default, delete, >pre, >post + +## Example + +```cpp +#include +#include + +// simple function with a default argument, returning nothing +void f0(const std::string& arg = "world!") { + std::cout << "Hello, " << arg << '\n'; +} + +// the declaration is in namespace (file) scope +// (the definition is provided later) +int f1(); + +// function returning a pointer to f0, pre-C++11 style +void (*fp03())(const std::string&) { + return f0; +} + +// function returning a pointer to f0, with C++11 trailing return type +auto fp11() -> void(*)(const std::string&) { + return f0; +} + +int main() { + f0(); + fp03()("test!"); + fp11()("again!"); + int f2(std::string) noexcept; // declaration in function scope + std::cout << "f2(\"bad\"): " << f2("bad") << '\n'; + std::cout << "f2(\"42\"): " << f2("42") << '\n'; +} + +// simple non-member function returning int +int f1() { + return 007; +} + +// function with an exception specification and a function try block +int f2(std::string str) noexcept try { + return std::stoi(str); +} catch (const std::exception& e) { + std::cerr << "stoi() failed!\n"; + return 0; +} + +// deleted function, an attempt to call it results in a compilation error +void bar() = delete +#if __cpp_deleted_function + ("reason") +#endif +; +``` + +Possible output: + +``` +stoi() failed! +Hello, world! +Hello, test! +Hello, again! +f2("bad"): 0 +f2("42"): 42 +``` + +## Defect reports + +The following behavior-changing defect reports were applied retroactively to previously published C++ standards. + + + + + member functions defined in class could not have a parameter of or return its own class because it is incomplete + + + allowed + + + + + + a parameter could have cv-qualified `void` type + + + prohibited + + + + + + types that include pointers/references to array of unknown bound could not be parameters + + + such types are allowed + + + + + + member initializer list was not a part of function body + + + it is + + + + + + dependent type void could be used to declare a function taking no parameters + + + only non-dependent `void` is allowed + + + + + + defaulted or deleted functions could not be specified with override or final + + + allowed + + + + + + only special member functions could be user-provided + + + extended to all functions + + + + + + deleted functions could not have any parameter of an incomplete type or return an incomplete type + + + incomplete type allowed + + + + + + the completeness check on parameter type and return type of a function definition could be made outside the context of the function definition + + + only check in the context of the function definition + + + + + + return type deduction treated `return;` as `return void();` + + + simply deduce the return type as `void` in this case + + + + + + the implicit odr-use of a deleted virtual function was ill-formed + + + such odr-uses are exempt from the use prohibition + + + + + + return type deduction on functions returning `void` would fail if the declared return type is `decltype(auto)` + + + updated the deduction rule to handle this case + + + + + + function redeclarations could use return type deduction even if the initial declaration does not + + + not allowed + + + + + + `{}` could be a function body or an initializer at the same place + + + differentiated by the type of the declarator identifier + + + + + + the `declarator` in function definition could not be parenthesized + + + allowed + + + + + + the ambiguity resolution rule regarding parenthesized type names did not cover lambda expressions + + + covered + + + + + + in the definition of a member function in a class definition, the type of that class could not be the return type or parameter type due to the resolution of [CWG issue 1824](https://cplusplus.github.io/CWG/issues/1824.html) + + + only check in the function body + + + + + + the function body of a constructor did not include the initializations not specified in the constructor's regular function body + + + also includes these initializations + + + + + + a function definition with a `requires-clause` could define a non-templated function + + + prohibited + + + + + + explicit object member functions could not have out-of-class definitions + + + allowed + + + + + + unnamed explicit object parameters could have type `void` + + + prohibited + + + + +## See also + + + + C documentation for **Declaring functions** + + \ No newline at end of file From 2aee7f4f07d215a4852841fa265d1f0195213bb7 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 11:41:55 +0800 Subject: [PATCH 04/10] feat: migrate `cpp/language/functions/default_arguments` --- .../language/functions/default_arguments.mdx | 374 ++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 src/content/docs/cpp/language/functions/default_arguments.mdx diff --git a/src/content/docs/cpp/language/functions/default_arguments.mdx b/src/content/docs/cpp/language/functions/default_arguments.mdx new file mode 100644 index 0000000..8ae3d17 --- /dev/null +++ b/src/content/docs/cpp/language/functions/default_arguments.mdx @@ -0,0 +1,374 @@ +--- +title: Default arguments +sidebar: + order: 3 +cppdoc: + keys: ["cpp.lang.functions.default_arguments"] +--- + +import { Decl, DeclDoc } from "@components/decl-doc"; +import { DR, DRList } from "@components/defect-report"; +import { Revision, RevisionBlock } from "@components/revision"; +import Behavior from "@components/Behavior.astro"; +import DocLink from "@components/DocLink.astro"; + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + = /*$s:initializer*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:declarator*/ + = /*$s:initializer*/ + ``` + + + + + ```cpp cxx-mark + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + = /*$s:initializer*/ + ``` + + + + + ```cpp cxx-mark + /*$s:attr*//*$opt*/ + /*$s:decl-specifier-seq*/ /*$s:abstract-declarator*//*$opt*/ + = /*$s:initializer*/ + ``` + + + + Allows a function to be called without providing one or more trailing arguments. + + Indicated by using the syntax above for a parameter in the `parameter-list` of a function declaration. + + +Default arguments are used in place of the missing trailing arguments in a function call: + +```cpp +void point(int x = 3, int y = 4); + +point(1, 2); // calls point(1, 2) +point(1); // calls point(1, 4) +point(); // calls point(3, 4) +``` + +In a function declaration, after a parameter with a default argument, all subsequent parameters must: + +- have a default argument supplied in this or a previous declaration from the same scope unless the parameter was expanded from a parameter pack: + +```cpp +int x(int = 1, int); // Error: only the trailing parameters can have default arguments + // (assuming there's no previous declaration of “x”) + +void f(int n, int k = 1); +void f(int n = 0, int k); // OK: the default argument of “k” is provided by + // the previous declaration in the same scope + +void g(int, int = 7); + +void h() { + void g(int = 1, int); // Error: not the same scope +} +``` + + + ```cpp + template + struct C { void f(int n = 0, T...); }; + + C c; // OK; instantiates declaration void C::f(int n = 0, int) + ``` + + + + - or be a function parameter pack: + + ```cpp + template + void h(int i = 0, T... args); // OK + ``` + + +The ellipsis is not a parameter, and so can follow a parameter with a default argument: + +```cpp +int g(int n = 0, ...); // OK +``` + +Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations. Template parameter lists use similar syntax for their default template arguments. + +For non-template functions, default arguments can be added to a function that was already declared if the function is redeclared in the same scope. At the point of a function call, the default arguments are a union of the default arguments provided in all visible declarations for the function. A redeclaration cannot introduce a default argument for a parameter for which a default argument is already visible (even if the value is the same). A re-declaration in an inner scope does not acquire the default arguments from outer scopes. + +```cpp +void f(int, int); // #1 +void f(int, int = 7); // #2 OK: adds a default argument + +void h() { + f(3); // #1 and #2 are in scope; makes a call to f(3,7) + void f(int = 1, int); // Error: the default argument of the second + // parameter is not acquired from outer scopes +} + +void m() { // new scope begins + void f(int, int); // inner scope declaration; has no default argument. + f(4); // Error: not enough arguments to call f(int, int) + void f(int, int = 6); + f(4); // OK: calls f(4, 6); + void f(int, int = 6); // Error: the second parameter already has a + // default argument (even if the values are the same) +} + +void f(int = 1, int); // #3 OK, adds a default argument to #2 + +void n() { // new scope begins + f(); // #1, #2, and #3 are in scope: calls f(1, 7); +} +``` + +If an inline function is declared in different translation units, the accumulated sets of default arguments must be the same at the end of each translation unit. + + + If a non-inline function is declared in the same namespace scope in different translation units, the corresponding default arguments must be the same if present (but some default arguments can be absent in some TU). + + +If a friend declaration specifies a default argument, it must be a friend function definition, and no other declarations of this function are allowed in the translation unit. + +The using-declarations carries over the set of known default arguments, and if more default arguments are added later to the function's namespace, those default arguments are also visible anywhere the using-declaration is visible: + +```cpp +namespace N { + void f(int, int = 1); +} + +using N::f; + +void g() { + f(7); // calls f(7, 1); + f(); // error +} + +namespace N { + void f(int = 2, int); +} + +void h() { + f(); // calls f(2, 1); +} +``` + +The names used in the default arguments are looked up, checked for accessibility, and bound at the point of declaration, but are executed at the point of the function call: + +```cpp +int a = 1; + +int f(int); + +int g(int x = f(a)); // lookup for f finds ::f, lookup for a finds ::a + // the value of ::a, which is 1 at this point, is not used + +void h() { + a = 2; // changes the value of ::a + { + int a = 3; + g(); // calls f(2), then calls g() with the result + } +} +``` + +For a member function of a non-templated class, the default arguments are allowed on the out-of-class definition, and are combined with the default arguments provided by the declaration inside the class body. If these out-of-class default arguments would turn a member function into a default constructor or copy/move constructor/assignment operator (which makes the call ambiguous), the program is ill-formed. For member functions of templated classes, all default arguments must be provided in the initial declaration of the member function. + +```cpp +class C { + void f(int i = 3); + void g(int i, int j = 99); + C(int arg); // non-default constructor +}; + +void C::f(int i = 3) {} // error: default argument already + // specified in class scope + +void C::g(int i = 88, int j) {} // OK: in this translation unit, + // C::g can be called with no argument + +C::C(int arg = 1) {} // Error: turns this into a default constructor +``` + +The overriders of virtual functions do not acquire the default arguments from the base class declarations, and when the virtual function call is made, the default arguments are decided based on the static type of the object (note: this can be avoided with [non-virtual interface](http://www.gotw.ca/publications/mill18.htm) pattern). + +```cpp +struct Base { + virtual void f(int a = 7); +}; + +struct Derived : Base { + void f(int a) override; +}; + +void m() { + Derived d; + Base& b = d; + b.f(); // OK: calls Derived::f(7) + d.f(); // Error: no default argument +} +``` + +Local variables are not allowed in default arguments unless they are not evaluated: + +```cpp +void f() { + int n = 1; + extern void g(int x = n); // error: local variable cannot be a default argument + extern void h(int x = sizeof n); // OK as of CWG 2082 +} +``` + +The this pointer is not allowed in default arguments: + +```cpp +class A { + void f(A* p = this) {} // error: this is not allowed +}; +``` + +Non-static class members are not allowed in default arguments (even if they are not evaluated), except when used to form a pointer-to-member or in a member access expression: + +```cpp +int b; + +class X { + int a; + int mem1(int i = a); // error: non-static member cannot be used + int mem2(int i = b); // OK: lookup finds X::b, the static member + int mem3(int X::* i = &X::a); // OK: non-static member can be used + int mem4(int i = x.a); // OK: in a member access expression + + static X x; + static int b; +}; +``` + +A default argument is evaluated each time the function is called with no argument for the corresponding parameter. Function parameters are not allowed in default arguments except if they are not evaluated. Note that parameters that appear earlier in the parameter list are in scope: + +```cpp +int a; + +int f(int a, int b = a); // Error: the parameter a used in a default argument + +int g(int a, int b = sizeof a); // Error until resolving CWG 2082 + // OK after resolution: use in unevaluated context is OK +``` + +The default arguments are not part of the function type: + +```cpp +int f(int = 0); + +void h() { + int j = f(1); + int k = f(); // calls f(0); +} + +int (*p1)(int) = &f; +int (*p2)() = &f; // Error: the type of f is int(int) +``` + +Operator functions other than the function call operator and the subscript operator cannot have default arguments: + +```cpp +class C { + int operator++(int i = 0); // ill-formed + int operator[](int j = 0); // OK since C++23 + int operator()(int k = 0); // OK +}; +``` + + + Explicit object parameters cannot have default arguments: + + ```cpp + struct S { void f(this const S& = S{}); }; // ill-formed + ``` + + +## Notes + +Spaces may be necessary to avoid a compound assignment token if the parameter name is absent (see maximal munch). + +```cpp +void f1(int*=0); // Error, “*=” is unexpected here +void g1(const int&=0); // Error, “&=” is unexpected here +void f2(int* = 0); // OK +void g2(const int& = 0); // OK +void h(int&&=0); // OK even without spaces, “&&” is a token here +``` + +## Defect reports + +The following behavior-changing defect reports were applied retroactively to previously published C++ standards. + + + + + a default argument could be added to a non-template member function of a class template + + + prohibited + + + + + + default arguments added in the out-of-class definition of a member function could change it to a special member function + + + prohibited + + + + + + default arguments were evaluated each time the function is called, even if the caller provided the arguments + + + evaluated only if no argument is provided for the corresponding parameter + + + + + + default arguments were forbidden to use local variables and preceding parameters in unevaluated context + + + unevaluated context use allowed + + + + + + parameters expanded from parameter packs could not appear after parameters with default arguments + + + allowed + + + + + + out-of-class definitions of the member functions of class templates' nested classes could have default arguments + + + prohibited + + + \ No newline at end of file From 1b952169692bff81544f281c76b22f7dcc87da61 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 11:57:24 +0800 Subject: [PATCH 05/10] feat: migrate `/cpp/language/functions/variadic_arguments` --- .../language/functions/variadic_arguments.mdx | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 src/content/docs/cpp/language/functions/variadic_arguments.mdx diff --git a/src/content/docs/cpp/language/functions/variadic_arguments.mdx b/src/content/docs/cpp/language/functions/variadic_arguments.mdx new file mode 100644 index 0000000..697f59e --- /dev/null +++ b/src/content/docs/cpp/language/functions/variadic_arguments.mdx @@ -0,0 +1,175 @@ +--- +title: Variadic arguments +sidebar: + order: 4 +cppdoc: + keys: ["cpp.lang.functions.variadic_arguments"] +--- + +import { Decl, DeclDoc } from "@components/decl-doc"; +import { DR, DRList } from "@components/defect-report"; +import { Desc, DescList, DocLink } from '@components/index'; +import { autoRev, Revision, RevisionBlock } from "@components/revision"; +import Behavior from "@components/Behavior.astro"; +import Missing from "@components/Missing.astro"; + +Allows a function to accept any number of extra arguments. + +A function is a variadic if the last parameter of its parameter list is an ellipsis (`...`). + + + The comma preceding the ellipsis can be omitted. + + +```cpp +// the function declared as follows +int printx(const char* fmt, ...); +int printx(const char* fmt...); // same as above, but deprecated since C++26 + +// may be called with one or more arguments: +printx("hello world"); +printx("a=%d b=%d", a, b); + +int printy(..., const char* fmt); // error: ... can only be the last parameter +int printz(...); // valid, but the arguments cannot be accessed portably +``` + + + This is different from a function parameter pack expansion, which is indicated by an ellipsis that is a part of a parameter declarator, rather than an ellipsis being a parameter alone. Both parameter pack expansion and the “variadic” ellipsis may appear in the declaration of a function template, as in the case of `std::is_function`. + + +## Default argument promotions + +When a variadic function is called, after lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions, each argument that is a part of the variable argument list undergoes additional conversions known as _default argument promotions_: + + + - `std::nullptr_t` is converted to `void*`. + + +- `float` arguments are converted to `double` as in floating-point promotion. +- `bool`, `char`, `short`, and unscoped enumerations are converted to `int` or wider integer types as in integral promotion. + +Non-POD class typesScoped enumerations and class types with an eligible non-trivial copy constructor, an eligible non-trivial move constructor, or a non-trivial destructor are conditionally-supported in potentially-evaluated calls with implementation-defined semantics (these types are always supported in unevaluated calls). + +Because variadic parameters have the lowest rank for the purpose of overload resolution, they are commonly used as the catch-all fallbacks in SFINAE. + +Within the body of a function that uses variadic arguments, the values of these arguments may be accessed using the \ library facilities: + + + + + `va_start` + + + enables access to variadic function arguments + + + + `va_arg` + + + accesses the next variadic function argument + + + + `va_copy` + + + makes a copy of the variadic function arguments + + + + `va_end` + + + ends traversal of the variadic function arguments + + + + `va_list` + + + holds the information needed by `va_start`, `va_arg`, `va_copy`, and `va_end` + + + +The behavior of the `va_start` macro is undefined if the last parameter before the ellipsis has reference type, or has type that is not compatible with the type that results from default argument promotions. + + + If the a pack expansion or an entity resulting from a lambda capture is used as the last parameter in `va_start`, the program is ill-formed, no diagnostic required. + + +
+ ## Alternatives :badge[C++11] + + - Variadic templates can also be used to create functions that take variable number of arguments. They are often the better choice because they do not impose restrictions on the types of the arguments, do not perform integral and floating-point promotions, and are type safe. + - If all variable arguments share a common type, a `std::initializer_list` provides a convenient mechanism (albeit with a different syntax) for accessing variable arguments. In this case however the arguments cannot be modified since `std::initializer_list` can only provide a const pointer to its elements. +
+ +## Notes + +In the C programming language until C23, at least one named parameter must appear before the ellipsis parameter, so `R printz(...);` is not valid until C23. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution. + +This syntax for variadic arguments was introduced in 1983 C++ without the comma before the ellipsis. When C89 adopted function prototypes from C++, it replaced the syntax with one requiring the comma. For compatibility, C++98 accepts both C++-style `f(int n...)` and `C-style f(int n, ...)`. The original C++-style grammar is deprecated since C++26. + + + The comma can be used in abbreviated function templates to make the ellipsis signify a variadic function instead of a variadic template: + + ```cpp + void f1(auto...); // same as template void f3(Ts...) + void f2(auto, ...); // same as template void f3(T, ...) + ``` + + +## Defect reports + +The following behavior-changing defect reports were applied retroactively to previously published C++ standards. + + + + + passing non-POD class arguments to an ellipsis resulted in undefined behavior + + + passing such arguments is conditionally-supported with implementation-defined semantics + + + + + + conditionally-supported class types made some SFINAE idioms not work + + + always supported if unevaluated + + + + + + no restriction on passing parameter pack or lambda capture to `va_start` + + + made ill-formed, no diagnostic required + + + + + + it was unclear whether scoped enumerations passed to an ellipsis are subject to default argument promotions + + + passing scoped enumerations is conditionally-supported with implementation-defined semantics + + + + +## See also + + + + C documentation for **Variadic arguments** + + + C documentation for **Implicit conversions** + + \ No newline at end of file From c42d32931ad14b90e3765ebc317d0775cebac831 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 12:00:25 +0800 Subject: [PATCH 06/10] fix: remove `import Missing` --- src/content/docs/cpp/language/functions/variadic_arguments.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/docs/cpp/language/functions/variadic_arguments.mdx b/src/content/docs/cpp/language/functions/variadic_arguments.mdx index 697f59e..109af06 100644 --- a/src/content/docs/cpp/language/functions/variadic_arguments.mdx +++ b/src/content/docs/cpp/language/functions/variadic_arguments.mdx @@ -11,7 +11,6 @@ import { DR, DRList } from "@components/defect-report"; import { Desc, DescList, DocLink } from '@components/index'; import { autoRev, Revision, RevisionBlock } from "@components/revision"; import Behavior from "@components/Behavior.astro"; -import Missing from "@components/Missing.astro"; Allows a function to accept any number of extra arguments. From 9f3c11613192b174035afdc2b82d8578a8e30711 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 12:05:33 +0800 Subject: [PATCH 07/10] fix: add newline at end of `_meta.yml` for consistency --- src/content/docs/cpp/language/functions/_meta.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/cpp/language/functions/_meta.yml b/src/content/docs/cpp/language/functions/_meta.yml index 09d8dd6..bbdcfca 100644 --- a/src/content/docs/cpp/language/functions/_meta.yml +++ b/src/content/docs/cpp/language/functions/_meta.yml @@ -1 +1 @@ -label: Functions \ No newline at end of file +label: Functions From 806728fc22aa7949d156506e1c054ef9f6677db8 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Tue, 16 Dec 2025 23:03:55 +0800 Subject: [PATCH 08/10] fix: remove all keys --- src/content/docs/cpp/language/functions.mdx | 2 -- src/content/docs/cpp/language/functions/default_arguments.mdx | 2 -- src/content/docs/cpp/language/functions/function.mdx | 2 -- src/content/docs/cpp/language/functions/variadic_arguments.mdx | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/content/docs/cpp/language/functions.mdx b/src/content/docs/cpp/language/functions.mdx index 543445d..64f4d62 100644 --- a/src/content/docs/cpp/language/functions.mdx +++ b/src/content/docs/cpp/language/functions.mdx @@ -2,8 +2,6 @@ title: Overview sidebar: order: 1 -cppdoc: - keys: ["cpp.lang.functions"] --- import { Revision, RevisionBlock } from "@components/revision"; diff --git a/src/content/docs/cpp/language/functions/default_arguments.mdx b/src/content/docs/cpp/language/functions/default_arguments.mdx index 8ae3d17..828c295 100644 --- a/src/content/docs/cpp/language/functions/default_arguments.mdx +++ b/src/content/docs/cpp/language/functions/default_arguments.mdx @@ -2,8 +2,6 @@ title: Default arguments sidebar: order: 3 -cppdoc: - keys: ["cpp.lang.functions.default_arguments"] --- import { Decl, DeclDoc } from "@components/decl-doc"; diff --git a/src/content/docs/cpp/language/functions/function.mdx b/src/content/docs/cpp/language/functions/function.mdx index eefdf64..f62b2a9 100644 --- a/src/content/docs/cpp/language/functions/function.mdx +++ b/src/content/docs/cpp/language/functions/function.mdx @@ -2,8 +2,6 @@ title: Function declaration sidebar: order: 2 -cppdoc: - keys: ["cpp.lang.functions.function"] --- import { Decl, DeclDoc } from "@components/decl-doc"; diff --git a/src/content/docs/cpp/language/functions/variadic_arguments.mdx b/src/content/docs/cpp/language/functions/variadic_arguments.mdx index 109af06..741b63f 100644 --- a/src/content/docs/cpp/language/functions/variadic_arguments.mdx +++ b/src/content/docs/cpp/language/functions/variadic_arguments.mdx @@ -2,8 +2,6 @@ title: Variadic arguments sidebar: order: 4 -cppdoc: - keys: ["cpp.lang.functions.variadic_arguments"] --- import { Decl, DeclDoc } from "@components/decl-doc"; From 869218d617ce0b9edcc0253f424fdc2b532fe606 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Wed, 17 Dec 2025 16:12:20 +0800 Subject: [PATCH 09/10] fix: replace src by dest --- src/content/docs/cpp/language/functions.mdx | 24 +-- .../language/functions/default_arguments.mdx | 28 ++-- .../docs/cpp/language/functions/function.mdx | 148 +++++++++--------- .../language/functions/variadic_arguments.mdx | 40 ++--- 4 files changed, 120 insertions(+), 120 deletions(-) diff --git a/src/content/docs/cpp/language/functions.mdx b/src/content/docs/cpp/language/functions.mdx index 64f4d62..137c23c 100644 --- a/src/content/docs/cpp/language/functions.mdx +++ b/src/content/docs/cpp/language/functions.mdx @@ -8,7 +8,7 @@ import { Revision, RevisionBlock } from "@components/revision"; import DocLink from "@components/DocLink.astro"; import NamedReq from "@components/NamedReq.astro"; -Functions are C++ entities that associate a sequence of statements (a _function body_) with a _name_ and a list of zero or more _function parameters_. +Functions are C++ entities that associate a sequence of statements (a _function body_) with a _name_ and a list of zero or more _function parameters_. ```cpp // function name: "isodd" @@ -19,7 +19,7 @@ bool isodd(int n) { // the body of the function begins } // the body of the function ends ``` -When a function is invoked, e.g. in a function-call expression, the parameters are initialized from the arguments (either provided at the place of call or defaulted) and the statements in the function body are executed. If the parameter list ends with `...`, extra arguments can be supplied to the function, such a function is called variadic function. +When a function is invoked, e.g. in a function-call expression, the parameters are initialized from the arguments (either provided at the place of call or defaulted) and the statements in the function body are executed. If the parameter list ends with `...`, extra arguments can be supplied to the function, such a function is called variadic function. ```cpp int main() { @@ -29,28 +29,28 @@ int main() { } ``` -Unqualified function names in function-call expressions are looked up with an extra set of rules called "argument-dependent lookup" (ADL). +Unqualified function names in function-call expressions are looked up with an extra set of rules called "argument-dependent lookup" (ADL). -A function can terminate by returning or by throwing an exception. +A function can terminate by returning or by throwing an exception. - A function may be a coroutine, in which case it can suspend execution to be resumed later. + A function may be a coroutine, in which case it can suspend execution to be resumed later. -A function declaration may appear in any scope, but a function definition may only appear in namespace scope or, for member and friend functions, in class scope. A function that is declared in a class body without a friend specifier is a class member function. Such functions have many additional properties, see member functions for details. +A function declaration may appear in any scope, but a function definition may only appear in namespace scope or, for member and friend functions, in class scope. A function that is declared in a class body without a friend specifier is a class member function. Such functions have many additional properties, see member functions for details. -Functions are not objects: there are no arrays of functions and functions cannot be passed by value or returned from other functions. Pointers and references to functions (except for the main function and most standard library functions) are allowed, and may be used where these functions themselves cannot. Therefore we say these functions are "addressable". +Functions are not objects: there are no arrays of functions and functions cannot be passed by value or returned from other functions. Pointers and references to functions (except for the main function and most standard library functions) are allowed, and may be used where these functions themselves cannot. Therefore we say these functions are "addressable". -Each function has a type, which consists of the function's return type, the types of all parameters (after array-to-pointer and function-to-pointer transformations, see parameter list) , whether the function is noexcept or not, and, for non-static member functions, cv-qualification and ref-qualification. Function types also have language linkage. There are no cv-qualified function types (not to be confused with the types of cv-qualified functions such as `int f() const;` or functions returning cv-qualified types, such as `std::string const f();`). Any cv-qualifier is ignored if it is added to an alias for a function type. +Each function has a type, which consists of the function's return type, the types of all parameters (after array-to-pointer and function-to-pointer transformations, see parameter list) , whether the function is noexcept or not, and, for non-static member functions, cv-qualification and ref-qualification. Function types also have language linkage. There are no cv-qualified function types (not to be confused with the types of cv-qualified functions such as `int f() const;` or functions returning cv-qualified types, such as `std::string const f();`). Any cv-qualifier is ignored if it is added to an alias for a function type. -Multiple functions in the same scope may have the same name, as long as their parameter lists and, for non-static member functions, cv/ref-qualifications are different. This is known as function overloading. Function declarations that differ only in the return type and the noexcept specification cannot be overloaded. The address of an overloaded function is determined differently. +Multiple functions in the same scope may have the same name, as long as their parameter lists and, for non-static member functions, cv/ref-qualifications are different. This is known as function overloading. Function declarations that differ only in the return type and the noexcept specification cannot be overloaded. The address of an overloaded function is determined differently. - C++ implements [anonymous functions](https://en.wikipedia.org/wiki/anonymous_function) using lambda-expressions. + C++ implements [anonymous functions](https://en.wikipedia.org/wiki/anonymous_function) using lambda-expressions. ## Function objects -Besides function lvalues, the function call expression supports pointers to functions, and any value of class type that overloads the function-call operator or is convertible to function pointer( including lambda-expressions). Together, these types are known as , and they are used ubiquitously through the C++ standard library, see for example, usages of and . +Besides function lvalues, the function call expression supports pointers to functions, and any value of class type that overloads the function-call operator or is convertible to function pointer( including lambda-expressions). Together, these types are known as , and they are used ubiquitously through the C++ standard library, see for example, usages of and . -The standard library also provides a number of predefined function object templates as well as the methods to compose new ones (including `std::less`, `std::mem_fn`, `std::bind`, `std::function`, `std::not_fn`, `std::bind_front`, `std::bind_back`, `std::move_only_function`, `std::copyable_function`, and `std::function_ref`). \ No newline at end of file +The standard library also provides a number of predefined function object templates as well as the methods to compose new ones (including `std::less`, `std::mem_fn`, `std::bind`, `std::function`, `std::not_fn`, `std::bind_front`, `std::bind_back`, `std::move_only_function`, `std::copyable_function`, and `std::function_ref`). \ No newline at end of file diff --git a/src/content/docs/cpp/language/functions/default_arguments.mdx b/src/content/docs/cpp/language/functions/default_arguments.mdx index 828c295..2cd3e76 100644 --- a/src/content/docs/cpp/language/functions/default_arguments.mdx +++ b/src/content/docs/cpp/language/functions/default_arguments.mdx @@ -48,7 +48,7 @@ import DocLink from "@components/DocLink.astro"; Allows a function to be called without providing one or more trailing arguments. - Indicated by using the syntax above for a parameter in the `parameter-list` of a function declaration. + Indicated by using the syntax above for a parameter in the `parameter-list` of a function declaration. Default arguments are used in place of the missing trailing arguments in a function call: @@ -104,7 +104,7 @@ The ellipsis is not a parameter, and so can follow a parameter with a default ar int g(int n = 0, ...); // OK ``` -Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations. Template parameter lists use similar syntax for their default template arguments. +Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations. Template parameter lists use similar syntax for their default template arguments. For non-template functions, default arguments can be added to a function that was already declared if the function is redeclared in the same scope. At the point of a function call, the default arguments are a union of the default arguments provided in all visible declarations for the function. A redeclaration cannot introduce a default argument for a parameter for which a default argument is already visible (even if the value is the same). A re-declaration in an inner scope does not acquire the default arguments from outer scopes. @@ -134,15 +134,15 @@ void n() { // new scope begins } ``` -If an inline function is declared in different translation units, the accumulated sets of default arguments must be the same at the end of each translation unit. +If an inline function is declared in different translation units, the accumulated sets of default arguments must be the same at the end of each translation unit. If a non-inline function is declared in the same namespace scope in different translation units, the corresponding default arguments must be the same if present (but some default arguments can be absent in some TU). -If a friend declaration specifies a default argument, it must be a friend function definition, and no other declarations of this function are allowed in the translation unit. +If a friend declaration specifies a default argument, it must be a friend function definition, and no other declarations of this function are allowed in the translation unit. -The using-declarations carries over the set of known default arguments, and if more default arguments are added later to the function's namespace, those default arguments are also visible anywhere the using-declaration is visible: +The using-declarations carries over the set of known default arguments, and if more default arguments are added later to the function's namespace, those default arguments are also visible anywhere the using-declaration is visible: ```cpp namespace N { @@ -165,7 +165,7 @@ void h() { } ``` -The names used in the default arguments are looked up, checked for accessibility, and bound at the point of declaration, but are executed at the point of the function call: +The names used in the default arguments are looked up, checked for accessibility, and bound at the point of declaration, but are executed at the point of the function call: ```cpp int a = 1; @@ -184,7 +184,7 @@ void h() { } ``` -For a member function of a non-templated class, the default arguments are allowed on the out-of-class definition, and are combined with the default arguments provided by the declaration inside the class body. If these out-of-class default arguments would turn a member function into a default constructor or copy/move constructor/assignment operator (which makes the call ambiguous), the program is ill-formed. For member functions of templated classes, all default arguments must be provided in the initial declaration of the member function. +For a member function of a non-templated class, the default arguments are allowed on the out-of-class definition, and are combined with the default arguments provided by the declaration inside the class body. If these out-of-class default arguments would turn a member function into a default constructor or copy/move constructor/assignment operator (which makes the call ambiguous), the program is ill-formed. For member functions of templated classes, all default arguments must be provided in the initial declaration of the member function. ```cpp class C { @@ -202,7 +202,7 @@ void C::g(int i = 88, int j) {} // OK: in this translation unit, C::C(int arg = 1) {} // Error: turns this into a default constructor ``` -The overriders of virtual functions do not acquire the default arguments from the base class declarations, and when the virtual function call is made, the default arguments are decided based on the static type of the object (note: this can be avoided with [non-virtual interface](http://www.gotw.ca/publications/mill18.htm) pattern). +The overriders of virtual functions do not acquire the default arguments from the base class declarations, and when the virtual function call is made, the default arguments are decided based on the static type of the object (note: this can be avoided with [non-virtual interface](http://www.gotw.ca/publications/mill18.htm) pattern). ```cpp struct Base { @@ -221,7 +221,7 @@ void m() { } ``` -Local variables are not allowed in default arguments unless they are not evaluated: +Local variables are not allowed in default arguments unless they are not evaluated: ```cpp void f() { @@ -231,7 +231,7 @@ void f() { } ``` -The this pointer is not allowed in default arguments: +The this pointer is not allowed in default arguments: ```cpp class A { @@ -256,7 +256,7 @@ class X { }; ``` -A default argument is evaluated each time the function is called with no argument for the corresponding parameter. Function parameters are not allowed in default arguments except if they are not evaluated. Note that parameters that appear earlier in the parameter list are in scope: +A default argument is evaluated each time the function is called with no argument for the corresponding parameter. Function parameters are not allowed in default arguments except if they are not evaluated. Note that parameters that appear earlier in the parameter list are in scope: ```cpp int a; @@ -281,7 +281,7 @@ int (*p1)(int) = &f; int (*p2)() = &f; // Error: the type of f is int(int) ``` -Operator functions other than the function call operator and the subscript operator cannot have default arguments: +Operator functions other than the function call operator and the subscript operator cannot have default arguments: ```cpp class C { @@ -292,7 +292,7 @@ class C { ``` - Explicit object parameters cannot have default arguments: + Explicit object parameters cannot have default arguments: ```cpp struct S { void f(this const S& = S{}); }; // ill-formed @@ -301,7 +301,7 @@ class C { ## Notes -Spaces may be necessary to avoid a compound assignment token if the parameter name is absent (see maximal munch). +Spaces may be necessary to avoid a compound assignment token if the parameter name is absent (see maximal munch). ```cpp void f1(int*=0); // Error, “*=” is unexpected here diff --git a/src/content/docs/cpp/language/functions/function.mdx b/src/content/docs/cpp/language/functions/function.mdx index f62b2a9..7ee7173 100644 --- a/src/content/docs/cpp/language/functions/function.mdx +++ b/src/content/docs/cpp/language/functions/function.mdx @@ -19,7 +19,7 @@ A function declaration introduces the function name and its type. A function def ## Function declaration -Function declarations may appear in any scope. A function declaration at class scope introduces a class member function (unless the `friend` specifier is used), see member functions and friend functions for details. +Function declarations may appear in any scope. A function declaration at class scope introduces a class member function (unless the `friend` specifier is used), see member functions and friend functions for details. @@ -63,7 +63,7 @@ Function declarations may appear in any scope. A function declaration at class s Trailing return type declaration. The `decl-specifier-seq` in this case must contain the keyword `auto`. -(see Declarations for the other forms of the `declarator` syntax) +(see Declarations for the other forms of the `declarator` syntax) @@ -77,13 +77,13 @@ Function declarations may appear in any scope. A function declaration at class s - dynamic exception specification + dynamic exception specification - either dynamic exception specification or noexcept specification + either dynamic exception specification or noexcept specification - noexcept specification + noexcept specification @@ -91,7 +91,7 @@ Function declarations may appear in any scope. A function declaration at class s - a list of attributes. These attributes are applied to the type of the function, not the function itself. The attributes for the function appear after the identifier within the declarator and are combined with the attributes that appear in the beginning of the declaration, if any. + a list of attributes. These attributes are applied to the type of the function, not the function itself. The attributes for the function appear after the identifier within the declarator and are combined with the attributes that appear in the beginning of the declaration, if any. const/volatile qualification, only allowed in non-static member function declarations @@ -103,10 +103,10 @@ Function declarations may appear in any scope. A function declaration at class s - As mentioned in Declarations, the declarator can be followed by a requires clause, which declares the associated constraints for the function, which must be satisfied in order for the function to be selected by overload resolution. (example: `void f1(int a) requires true;`) Note that the associated constraint is part of function signature, but not part of function type. + As mentioned in Declarations, the declarator can be followed by a requires clause, which declares the associated constraints for the function, which must be satisfied in order for the function to be selected by overload resolution. (example: `void f1(int a) requires true;`) Note that the associated constraint is part of function signature, but not part of function type. -Function declarators can be mixed with other declarators, where the declaration specifier sequence allows: +Function declarators can be mixed with other declarators, where the declaration specifier sequence allows: ```cpp // declares an int, an int*, a function, and a pointer to a function @@ -146,7 +146,7 @@ The return type of a function cannot be a function type or an array type (but ca
## Return type deduction :badge[C++14] - f the `decl-specifier-seq` of the function declaration contains the keyword `auto`, trailing return type may be omitted, and will be deduced by the compiler from the type of the operand used in the non-discarded return statement. If the return type does not use `decltype(auto)`, the deduction follows the rules of template argument deduction: + f the `decl-specifier-seq` of the function declaration contains the keyword `auto`, trailing return type may be omitted, and will be deduced by the compiler from the type of the operand used in the non-discarded return statement. If the return type does not use `decltype(auto)`, the deduction follows the rules of template argument deduction: ```cpp int x = 1; @@ -154,7 +154,7 @@ The return type of a function cannot be a function type or an array type (but ca const auto& f() { return x; } // return type is const int& ``` - If the return type is `decltype(auto)`, the return type is as what would be obtained if the operand used in the return statement were wrapped in decltype: + If the return type is `decltype(auto)`, the return type is as what would be obtained if the operand used in the return statement were wrapped in decltype: ```cpp int x = 1; @@ -192,13 +192,13 @@ The return type of a function cannot be a function type or an array type (but ca } ``` - If the return statement uses a brace-enclosed initializer list, deduction is not allowed: + If the return statement uses a brace-enclosed initializer list, deduction is not allowed: ```cpp auto func() { return {1, 2, 3}; } // Error ``` - Virtual functions and coroutines cannot use return type deduction: + Virtual functions and coroutines cannot use return type deduction: ```cpp struct F { @@ -206,7 +206,7 @@ The return type of a function cannot be a function type or an array type (but ca }; ``` - Function templates other than user-defined conversion functions can use return type deduction. The deduction takes place at instantiation even if the expression in the return statement is not dependent. This instantiation is not in an immediate context for the purposes of SFINAE. + Function templates other than user-defined conversion functions can use return type deduction. The deduction takes place at instantiation even if the expression in the return statement is not dependent. This instantiation is not in an immediate context for the purposes of SFINAE. ```cpp template @@ -244,7 +244,7 @@ The return type of a function cannot be a function type or an array type (but ca // template auto g(char); // Error: not a specialization of the primary template g ``` - Explicit instantiation declarations do not themselves instantiate function templates that use return type deduction: + Explicit instantiation declarations do not themselves instantiate function templates that use return type deduction: ```cpp template @@ -278,7 +278,7 @@ The parameter list determines the arguments that can be specified when the funct - Declares a named (formal) parameter. For the meanings of `decl-specifier-seq` and `declarator`, see declarations. + Declares a named (formal) parameter. For the meanings of `decl-specifier-seq` and `declarator`, see declarations. ```cpp int f(int a, int* p, int (*(*x)(double))[3]); @@ -317,7 +317,7 @@ The parameter list determines the arguments that can be specified when the funct - Declares a named (formal) parameter with a default value. + Declares a named (formal) parameter with a default value. ```cpp int f(int a = 7, int* p = nullptr, int (*(*x)(double))[3] = nullptr); @@ -380,7 +380,7 @@ The parameter list determines the arguments that can be specified when the funct - Declares an unnamed parameter with a default value. + Declares an unnamed parameter with a default value. ```cpp int f(int = 7, int* = nullptr, int (*(*)(double))[3] = nullptr); @@ -416,7 +416,7 @@ The parameter list determines the arguments that can be specified when the funct `int f3(const void);` - `void` is dependent + `void` is dependent `int f4(T);` (where `T` is `void`) @@ -431,11 +431,11 @@ The parameter list determines the arguments that can be specified when the funct - Although `decl-specifier-seq` implies there can exist specifiers other than type specifiers, the only other specifier allowed is `register` as well as `auto`, and it has no effect. + Although `decl-specifier-seq` implies there can exist specifiers other than type specifiers, the only other specifier allowed is `register` as well as `auto`, and it has no effect. - If any of the function parameters uses a placeholder (either `auto` or a concept type), the function declaration is instead an abbreviated function template declaration: + If any of the function parameters uses a placeholder (either `auto` or a concept type), the function declaration is instead an abbreviated function template declaration: ```cpp void f1(auto); // same as template void f1(T) @@ -448,16 +448,16 @@ The parameter list determines the arguments that can be specified when the funct A parameter declaration with the specifier `this` (syntax (2)/(5)) declares an _explicit object parameter_. - An explicit object parameter cannot be a function parameter pack, and it can only appear as the first parameter of the parameter list in the following declarations: + An explicit object parameter cannot be a function parameter pack, and it can only appear as the first parameter of the parameter list in the following declarations: - - a declaration of a member function or member function template - - an explicit instantiation or explicit specialization of a templated member function - - a lambda declaration + - a declaration of a member function or member function template + - an explicit instantiation or explicit specialization of a templated member function + - a lambda declaration A member function with an explicit object parameter has the following restrictions: - - The function is not static. - - The function is not virtual. + - The function is not static. + - The function is not virtual. - The declarator of the function does not contain `cv` and `ref`. ```cpp @@ -480,7 +480,7 @@ The parameter list determines the arguments that can be specified when the funct Parameter names declared in function declarations are usually for only self-documenting purposes. They are used (but remain optional) in function definitions. -An ambiguity arises in a parameter list when a type name is nested in parentheses (including lambda expressions). In this case, the choice is between the declaration of a parameter of type pointer to function and the declaration of a parameter with redundant parentheses around the identifier of the `declarator`. The resolution is to consider the type name as a simple type specifier (which is the pointer to function type): +An ambiguity arises in a parameter list when a type name is nested in parentheses (including lambda expressions). In this case, the choice is between the declaration of a parameter of type pointer to function and the declaration of a parameter with redundant parentheses around the identifier of the `declarator`. The resolution is to consider the type name as a simple type specifier (which is the pointer to function type): ```cpp class C {}; @@ -496,7 +496,7 @@ Parameter type cannot be a type that includes a reference or a pointer to array ### Using an ellipsis -The last parameter in the parameter list can be an ellipsis (`...`); this declares a variadic function. The comma preceding the ellipsis can be omitted: +The last parameter in the parameter list can be an ellipsis (`...`); this declares a variadic function. The comma preceding the ellipsis can be omitted: ```cpp int printf(const char* fmt, ...); // a variadic function @@ -518,10 +518,10 @@ void f(Args......); // same as above, but deprecated since C++26 A function’s _parameter-type-list_ is determined as follows: -1. The type of each parameter (including function parameter packs) is determined from its own [parameter declaration](#parameter-list). +1. The type of each parameter (including function parameter packs) is determined from its own [parameter declaration](#parameter-list). 2. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. -3. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. -4. The resulting list of transformed parameter types and the presence or absence of the [ellipsis](#using-an-ellipsis) or a function parameter pack is the function’s parameter-type-list. +3. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. +4. The resulting list of transformed parameter types and the presence or absence of the [ellipsis](#using-an-ellipsis) or a function parameter pack is the function’s parameter-type-list. ```cpp void f(char*); // #1 @@ -542,7 +542,7 @@ void h(int (*)(int)) {} // defines #3 In syntax (1), assuming `noptr-declarator` as a standalone declaration, given the type of the `qualified-id` or `unqualified-id` in `noptr-declarator` as “derived-declarator-type-list T”: - - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning T”. + - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning T”. - TheOtherwise, the type of the function declared is “derived-declarator-type-list function of parameter-type-list `cv` (optional) `ref` (optional) returning T”. @@ -552,7 +552,7 @@ In syntax (1), assuming `noptr-declarator` as a standalone declaration, given th - - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning `trailing`”. + - If the exception specification is non-throwing, the type of the function declared is “derived-declarator-type-list `noexcept` function of parameter-type-list `cv` (optional) `ref` (optional) returning `trailing`”. @@ -579,12 +579,12 @@ struct X { ### Trailing qualifiers -A function type with `cv` or `ref` (including a type named by typedef name) can appear only as: +A function type with `cv` or `ref` (including a type named by typedef name) can appear only as: -- the function type for a non-static member function, +- the function type for a non-static member function, - the function type to which a pointer to member refers, -- the top-level function type of a function `typedef` declaration or alias declaration, -- the type-id in the default argument of a template type parameter, or +- the top-level function type of a function `typedef` declaration or alias declaration, +- the type-id in the default argument of a template type parameter, or - the type-id of a template argument for a template type parameter. ```cpp @@ -602,9 +602,9 @@ FIC S::*pm = &S::f; // OK Every function has a signature. -The signature of a function consists of its name and [parameter-type-list](#parameter-type-list). Its signature also contains the enclosing namespace, with the following exceptions: +The signature of a function consists of its name and [parameter-type-list](#parameter-type-list). Its signature also contains the enclosing namespace, with the following exceptions: -- If the function is a member function, its signature contains the class of which the function is a member instead of the enclosing namespace. Its signature also contains the following components, if exists: +- If the function is a member function, its signature contains the class of which the function is a member instead of the enclosing namespace. Its signature also contains the following components, if exists: - `cv` - `ref` @@ -614,10 +614,10 @@ The signature of a function consists of its name and [parameter-type-list](#para - - If the function is a non-template friend function with a trailing requires clause, its signature contains the enclosing class instead of the enclosing namespace. The signature also contains the trailing requires clause. + - If the function is a non-template friend function with a trailing requires clause, its signature contains the enclosing class instead of the enclosing namespace. The signature also contains the trailing requires clause. -`except` and `attr` doesn't involve function signature, although noexcept specification affects the function type. +`except` and `attr` doesn't involve function signature, although noexcept specification affects the function type. ## Function definition @@ -690,7 +690,7 @@ A non-member function definition may appear at namespace scope only (there are n - the return type with specifiers, as in the declaration grammar + the return type with specifiers, as in the declaration grammar function declarator, same as in the function declaration grammar above (can be parenthesized) @@ -703,10 +703,10 @@ A non-member function definition may appear at namespace scope only (there are n - a list of attributes. These attributes are combined with the attributes after the identifier in the `declarator` (see top of this page), if any. + a list of attributes. These attributes are combined with the attributes after the identifier in the `declarator` (see top of this page), if any. - override, final, or their combination in any order + override, final, or their combination in any order @@ -714,7 +714,7 @@ A non-member function definition may appear at namespace scope only (there are n - a requires clause + a requires clause @@ -746,7 +746,7 @@ A non-member function definition may appear at namespace scope only (there are n ``` - Function try block. + Function try block. @@ -787,20 +787,20 @@ A non-member function definition may appear at namespace scope only (there are n - member initializer list, only allowed in constructors + member initializer list, only allowed in constructors - the brace-enclosed sequence of statements that constitutes the body of a function + the brace-enclosed sequence of statements that constitutes the body of a function - a function try block + a function try block - an unevaluated string literal that could be used to explain the rationale for why the function is deleted + an unevaluated string literal that could be used to explain the rationale for why the function is deleted @@ -816,13 +816,13 @@ int max(int a, int b, int c) { // body is { ... } ``` -The function body is a compound statement (sequence of zero or more statements surrounded by a pair of curly braces), which is executed when the function call is made. Moreover, the function body of a constructor also includes the following: +The function body is a compound statement (sequence of zero or more statements surrounded by a pair of curly braces), which is executed when the function call is made. Moreover, the function body of a constructor also includes the following: -- For all non-static data members whose identifiers are absent in the constructor's member initializer list, the default member initializers or default-initializations used to initialize the corresponding member subobjects. +- For all non-static data members whose identifiers are absent in the constructor's member initializer list, the default member initializers or default-initializations used to initialize the corresponding member subobjects. - For all base classes whose type names are absent in the constructor's member initializer list, the default-initializations used to initialize the corresponding base class subobjects. - If a function definition contains a `virt-specs`, it must define a member function. + If a function definition contains a `virt-specs`, it must define a member function. ```cpp void f() override {} // Error: not a member function @@ -830,16 +830,16 @@ The function body is a - If a function definition contains a `requires-clause`, it must define a templated function. + If a function definition contains a `requires-clause`, it must define a templated function. ```cpp void g() requires (sizeof(int) == 4) {} // Error: not a templated function ``` -The parameter types, as well as the return type of a function definition cannot be (possibly cv-qualified) incomplete class types unless the function is defined as deleted. The completeness check is only made in the function body, which allows member functions to return the class in which they are defined (or its enclosing class), even if it is incomplete at the point of definition (it is complete in the function body). +The parameter types, as well as the return type of a function definition cannot be (possibly cv-qualified) incomplete class types unless the function is defined as deleted. The completeness check is only made in the function body, which allows member functions to return the class in which they are defined (or its enclosing class), even if it is incomplete at the point of definition (it is complete in the function body). -The parameters declared in the `declarator` of a function definition are in scope within the body. If a parameter is not used in the function body, it does not need to be named (it's sufficient to use an abstract declarator): +The parameters declared in the `declarator` of a function definition are in scope within the body. If a parameter is not used in the function body, it does not need to be named (it's sufficient to use an abstract declarator): ```cpp void print(int a, int) // second parameter is not used @@ -848,7 +848,7 @@ void print(int a, int) // second parameter is not used } ``` -Even though top-level cv-qualifiers on the parameters are discarded in function declarations, they modify the type of the parameter as visible in the body of a function: +Even though top-level cv-qualifiers on the parameters are discarded in function declarations, they modify the type of the parameter as visible in the body of a function: ```cpp void f(const int n) // declares function of type void(int) @@ -862,7 +862,7 @@ void f(const int n) // declares function of type void(int) If `function-body` is of syntax (3), the function is defined as _explicitly defaulted_. - A function that is explicitly defaulted must be a special member function or comparison operator function, and it must have no default argument. + A function that is explicitly defaulted must be a special member function or comparison operator function, and it must have no default argument. An explicitly defaulted special member function F1 is allowed to differ from the corresponding special member function F2 that would have been implicitly declared, as follows: @@ -879,7 +879,7 @@ void f(const int n) // declares function of type void(int) - Otherwise, if F1 is explicitly defaulted on its first declaration, it is defined as deleted. - Otherwise, the program is ill-formed. - A function explicitly defaulted on its first declaration is implicitly inline, and is implicitly constexpr if it can be a constexpr function. + A function explicitly defaulted on its first declaration is implicitly inline, and is implicitly constexpr if it can be a constexpr function. ```cpp struct S { @@ -900,15 +900,15 @@ void f(const int n) // declares function of type void(int) If `function-body` is of syntax (4) or (5), the function is defined as _explicitly deleted_. - Any use of a deleted function is ill-formed (the program will not compile). This includes calls, both explicit (with a function call operator) and implicit (a call to deleted overloaded operator, special member function, allocation function, etc), constructing a pointer or pointer-to-member to a deleted function, and even the use of a deleted function in an expression that is not potentially-evaluated. + Any use of a deleted function is ill-formed (the program will not compile). This includes calls, both explicit (with a function call operator) and implicit (a call to deleted overloaded operator, special member function, allocation function, etc), constructing a pointer or pointer-to-member to a deleted function, and even the use of a deleted function in an expression that is not potentially-evaluated. - A non-pure virtual member function can be defined as deleted, even though it is implicitly odr-used. A deleted function can only be overridden by deleted functions, and a non-deleted function can only be overridden by non-deleted functions. + A non-pure virtual member function can be defined as deleted, even though it is implicitly odr-used. A deleted function can only be overridden by deleted functions, and a non-deleted function can only be overridden by non-deleted functions. If `string-literal` is present, the implementation is encouraged to include the text of it as part of the resulting diagnostic message which shows the rationale for deletion or to suggest an alternative. - If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected: + If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected: ```cpp struct T { @@ -956,7 +956,7 @@ void f(const int n) // declares function of type void(int) ### Ambiguity Resolution :badge[C++11] - In the case of an ambiguity between a function body and an initializer beginning with `{` or `=`, the ambiguity is resolved by checking the type of the declarator identifier of `noptr-declarator`: + In the case of an ambiguity between a function body and an initializer beginning with `{` or `=`, the ambiguity is resolved by checking the type of the declarator identifier of `noptr-declarator`: - If the type is a function type, the ambiguous token sequence is treated as a function body. - Otherwise, the ambiguous token sequence is treated as an initializer. @@ -1019,7 +1019,7 @@ void f(const int n) // declares function of type void(int)
## Function contract specifiers :badge[C++26] - Function declarations and lambda expressions can contain a sequence of _function contract specifiers_, each specifier has the following syntax: + Function declarations and lambda expressions can contain a sequence of _function contract specifiers_, each specifier has the following syntax: @@ -1056,7 +1056,7 @@ void f(const int n) // declares function of type void(int) a list of attributes appertaining to the introduced contract assertion - any expression (except unparenthesized comma expressions) + any expression (except unparenthesized comma expressions) the identifier that refers to the result @@ -1068,11 +1068,11 @@ void f(const int n) // declares function of type void(int) Precondition assertion and postcondition assertion are collectively called _function contract assertion_. - A function contract assertion is a contract assertion associated with a function. The predicate of a function contract assertion is its `predicate` contextually converted to `bool`. + A function contract assertion is a contract assertion associated with a function. The predicate of a function contract assertion is its `predicate` contextually converted to `bool`. The following functions cannot be declared with function contract specifiers: - - virtual functions + - virtual functions - [deleted functions](#deleted-functions) - function [defaulted](#defaulted-functions) on their first declarations @@ -1115,7 +1115,7 @@ void f(const int n) // declares function of type void(int) void f() post(r : r > 0); // Error: no value can be bound to “r” ``` - When the declared return type of a non-templated function contains a placeholder type, a postcondition assertion with an `identifier` can only appear in a function definition: + When the declared return type of a non-templated function contains a placeholder type, a postcondition assertion with an `identifier` can only appear in a function definition: ```cpp auto g(auto&) post(r : r >= 0); // OK, “g” is a template @@ -1130,7 +1130,7 @@ void f(const int n) // declares function of type void(int) ### Contract consistency - A redeclaration D of a function or function template `func` must have either no `contract-specs` or the same contract-specs as any first declaration F reachable from D. If D and F are in different translation units, a diagnostic is required only if D is attached to a named module. + A redeclaration D of a function or function template `func` must have either no `contract-specs` or the same contract-specs as any first declaration F reachable from D. If D and F are in different translation units, a diagnostic is required only if D is attached to a named module. If a declaration F1 is a first declaration of func in one translation unit and a declaration F2 is a first declaration of `func` in another translation unit, F1 and F2 must specify the same `contract-specs`, no diagnostic required. @@ -1138,7 +1138,7 @@ void f(const int n) // declares function of type void(int) A function contract specifier C1 on a function declaration D1 is the same as a function contract specifier C2 on a function declaration D2 if all following conditions are satisfied: - - The `predicate`s of C1 and C2 would satisfy the one-definition rule if placed in function definitions on the declarations D1 and D2 (if D1 and D2 are in different translation units, corresponding entities defined within each `predicate` behave as if there is a single entity with a single definition), respectively, except for the following renamings: + - The `predicate`s of C1 and C2 would satisfy the one-definition rule if placed in function definitions on the declarations D1 and D2 (if D1 and D2 are in different translation units, corresponding entities defined within each `predicate` behave as if there is a single entity with a single definition), respectively, except for the following renamings: - The renaming of the parameters of the declared function. - The renaming of template parameters of a template enclosing the declared function. - The renaming of the result binding (if any). @@ -1168,11 +1168,11 @@ void f(const int n) // declares function of type void(int) ## Notes -In case of ambiguity between a variable declaration using the direct-initialization syntax and a function declaration, the compiler always chooses function declaration; see direct-initialization. +In case of ambiguity between a variable declaration using the direct-initialization syntax and a function declaration, the compiler always chooses function declaration; see direct-initialization. - decltype(auto) + decltype(auto) @@ -1184,7 +1184,7 @@ In case of ambiguity between a variable declaration using the direct-initializat - [explicit object parameters](#explicit-object-parameter) (deducing this) + [explicit object parameters](#explicit-object-parameter) (deducing this) @@ -1196,7 +1196,7 @@ In case of ambiguity between a variable declaration using the direct-initializat ## Keywords -default, delete, >pre, >post +default, delete, >pre, >post ## Example diff --git a/src/content/docs/cpp/language/functions/variadic_arguments.mdx b/src/content/docs/cpp/language/functions/variadic_arguments.mdx index 741b63f..5c11187 100644 --- a/src/content/docs/cpp/language/functions/variadic_arguments.mdx +++ b/src/content/docs/cpp/language/functions/variadic_arguments.mdx @@ -12,7 +12,7 @@ import Behavior from "@components/Behavior.astro"; Allows a function to accept any number of extra arguments. -A function is a variadic if the last parameter of its parameter list is an ellipsis (`...`). +A function is a variadic if the last parameter of its parameter list is an ellipsis (`...`). The comma preceding the ellipsis can be omitted. @@ -32,80 +32,80 @@ int printz(...); // valid, but the arguments cannot be accessed portably ``` - This is different from a function parameter pack expansion, which is indicated by an ellipsis that is a part of a parameter declarator, rather than an ellipsis being a parameter alone. Both parameter pack expansion and the “variadic” ellipsis may appear in the declaration of a function template, as in the case of `std::is_function`. + This is different from a function parameter pack expansion, which is indicated by an ellipsis that is a part of a parameter declarator, rather than an ellipsis being a parameter alone. Both parameter pack expansion and the “variadic” ellipsis may appear in the declaration of a function template, as in the case of `std::is_function`. ## Default argument promotions -When a variadic function is called, after lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions, each argument that is a part of the variable argument list undergoes additional conversions known as _default argument promotions_: +When a variadic function is called, after lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions, each argument that is a part of the variable argument list undergoes additional conversions known as _default argument promotions_: - - `std::nullptr_t` is converted to `void*`. + - `std::nullptr_t` is converted to `void*`. -- `float` arguments are converted to `double` as in floating-point promotion. -- `bool`, `char`, `short`, and unscoped enumerations are converted to `int` or wider integer types as in integral promotion. +- `float` arguments are converted to `double` as in floating-point promotion. +- `bool`, `char`, `short`, and unscoped enumerations are converted to `int` or wider integer types as in integral promotion. -Non-POD class typesScoped enumerations and class types with an eligible non-trivial copy constructor, an eligible non-trivial move constructor, or a non-trivial destructor are conditionally-supported in potentially-evaluated calls with implementation-defined semantics (these types are always supported in unevaluated calls). +Non-POD class typesScoped enumerations and class types with an eligible non-trivial copy constructor, an eligible non-trivial move constructor, or a non-trivial destructor are conditionally-supported in potentially-evaluated calls with implementation-defined semantics (these types are always supported in unevaluated calls). -Because variadic parameters have the lowest rank for the purpose of overload resolution, they are commonly used as the catch-all fallbacks in SFINAE. +Because variadic parameters have the lowest rank for the purpose of overload resolution, they are commonly used as the catch-all fallbacks in SFINAE. -Within the body of a function that uses variadic arguments, the values of these arguments may be accessed using the \ library facilities: +Within the body of a function that uses variadic arguments, the values of these arguments may be accessed using the \ library facilities: - `va_start` + `va_start` enables access to variadic function arguments - `va_arg` + `va_arg` accesses the next variadic function argument - `va_copy` + `va_copy` makes a copy of the variadic function arguments - `va_end` + `va_end` ends traversal of the variadic function arguments - `va_list` + `va_list` - holds the information needed by `va_start`, `va_arg`, `va_copy`, and `va_end` + holds the information needed by `va_start`, `va_arg`, `va_copy`, and `va_end` -The behavior of the `va_start` macro is undefined if the last parameter before the ellipsis has reference type, or has type that is not compatible with the type that results from default argument promotions. +The behavior of the `va_start` macro is undefined if the last parameter before the ellipsis has reference type, or has type that is not compatible with the type that results from default argument promotions. - If the a pack expansion or an entity resulting from a lambda capture is used as the last parameter in `va_start`, the program is ill-formed, no diagnostic required. + If the a pack expansion or an entity resulting from a lambda capture is used as the last parameter in `va_start`, the program is ill-formed, no diagnostic required.
## Alternatives :badge[C++11] - - Variadic templates can also be used to create functions that take variable number of arguments. They are often the better choice because they do not impose restrictions on the types of the arguments, do not perform integral and floating-point promotions, and are type safe. - - If all variable arguments share a common type, a `std::initializer_list` provides a convenient mechanism (albeit with a different syntax) for accessing variable arguments. In this case however the arguments cannot be modified since `std::initializer_list` can only provide a const pointer to its elements. + - Variadic templates can also be used to create functions that take variable number of arguments. They are often the better choice because they do not impose restrictions on the types of the arguments, do not perform integral and floating-point promotions, and are type safe. + - If all variable arguments share a common type, a `std::initializer_list` provides a convenient mechanism (albeit with a different syntax) for accessing variable arguments. In this case however the arguments cannot be modified since `std::initializer_list` can only provide a const pointer to its elements.
## Notes -In the C programming language until C23, at least one named parameter must appear before the ellipsis parameter, so `R printz(...);` is not valid until C23. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution. +In the C programming language until C23, at least one named parameter must appear before the ellipsis parameter, so `R printz(...);` is not valid until C23. In C++, this form is allowed even though the arguments passed to such function are not accessible, and is commonly used as the fallback overload in SFINAE, exploiting the lowest priority of the ellipsis conversion in overload resolution. This syntax for variadic arguments was introduced in 1983 C++ without the comma before the ellipsis. When C89 adopted function prototypes from C++, it replaced the syntax with one requiring the comma. For compatibility, C++98 accepts both C++-style `f(int n...)` and `C-style f(int n, ...)`. The original C++-style grammar is deprecated since C++26. From 156217afa177a9fbee583c5cd4101a39168a737e Mon Sep 17 00:00:00 2001 From: Sudrut Date: Wed, 17 Dec 2025 16:35:04 +0800 Subject: [PATCH 10/10] fix: replace src by dest --- src/content/docs/cpp/language/functions/function.mdx | 2 +- .../docs/cpp/language/functions/variadic_arguments.mdx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/cpp/language/functions/function.mdx b/src/content/docs/cpp/language/functions/function.mdx index 7ee7173..8ba5891 100644 --- a/src/content/docs/cpp/language/functions/function.mdx +++ b/src/content/docs/cpp/language/functions/function.mdx @@ -1463,6 +1463,6 @@ The following behavior-changing defect reports were applied retroactively to pre - C documentation for **Declaring functions** + C documentation for **Declaring functions** \ No newline at end of file diff --git a/src/content/docs/cpp/language/functions/variadic_arguments.mdx b/src/content/docs/cpp/language/functions/variadic_arguments.mdx index 5c11187..63d1699 100644 --- a/src/content/docs/cpp/language/functions/variadic_arguments.mdx +++ b/src/content/docs/cpp/language/functions/variadic_arguments.mdx @@ -164,9 +164,9 @@ The following behavior-changing defect reports were applied retroactively to pre - C documentation for **Variadic arguments** + C documentation for **Variadic arguments** - C documentation for **Implicit conversions** + C documentation for **Implicit conversions** \ No newline at end of file