首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Declaring functions

函数声明引入函数名称及其类型。函数定义将函数名/类型与函数体关联。

功能声明

函数声明可以出现在任何范围中。除非使用了%29,否则类作用域中的函数声明将引入类成员函数%28,请参见成员函数和朋友函数关于细节。

声明的函数的类型由返回类型的decl-说明符-seq提供的%28声明语法%29和函数声明器。

noptr-declarator ( parameter-list ) cv(optional) ref(optional) except(optional) attr(optional) requires(concepts TS)

(1)

?

noptr-declarator ( parameter-list ) cv(optional) ref(optional) except(optional) attr(optional) -> trailing requires(concepts TS)

(2)

(since C++11)

28%见声明对于其他形式的声明器语法%29。

1%29常规函数声明器语法

2%29尾随返回类型声明:只允许在最外层的函数声明器上使用尾部返回类型。在这种情况下,decl-说明符-seq必须包含关键字。auto

noptr-declarator

-

any valid declarator, but if it begins with *, &, or &&, it has to be surrounded by parentheses.

parameter-list

-

possibly empty, comma-separated list of the function parameters (see below for details)

attr(C++11)

-

optional 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.

cv

-

const/volatile qualification, only allowed in non-static member function declarations

ref(C++11)

-

ref-qualification, only allowed in non-static member function declarations

except

-

either dynamic exception specification(until C++17) or noexcept specification(C++11) Note that the exception specification is not part of the function type (until C++17)

trailing(C++11)

-

Trailing return type, useful if the return type depends on argument names, such as template <class T, class U> auto add(T t, U u) -> decltype(t + u); or is complicated, such as in auto fpif(int)->int(*)(int)

requires(concepts TS)

-

The 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. Note that the associated constraint is part of function signature, but not part of function type.

函数声明器可以与其他声明器混合,其中decl-说明符-seq允许:

二次

代码语言:javascript
复制
// 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
};

二次

函数的返回类型不能是函数类型或数组类型%28,但可以是指针或对%29的引用。

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). [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. void f() [noreturn]; // Error: this attribute has no effect on a type

(since C++11)

Return type deduction If 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 expression used in the return statement. If the return type does not use decltype(auto), the deduction follows the rules of template argument deduction. 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 expression used in the return statement were wrapped in decltype. 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. auto f(bool val) { if(val) return 123; // deduces return type int else return 3.14f; // deduces return type float: error } If there is no return statement or if the argument of the return statement is a void expression, 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. 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. 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-init-list, deduction is not allowed: auto func () { return {1, 2, 3}; } // error Virtual functions cannot use return type deduction. struct F { virtual auto f() { return 2; } // error }; If a function uses return type deduction, it cannot be redeclared using the type that it deduces to, or another kind of return type deduction even if it deduces to the same type. auto f(); // declared, not yet defined auto f() { return 42; } // defined, return type is int int f(); // error, cannot use the deduced type decltype(auto) f(); // error, different kind of deduction auto f(); // re-declared, OK template<typename T> struct A { friend T frf(T); }; auto frf(int i) { return i; } // not a friend of A<int> 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. template<class T> auto f(T t) { return t; } typedef decltype(f(1)) fint_t; // instantiates f<int> to deduce return type template<class T> auto f(T* t) { return *t; } void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types, // chooses second template overload Specializations of function templates that use return type deduction must use the same return type placeholders. template<typename T> auto g(T t) { return t; } // #1 template auto g(int); // OK, return type is int //template char g(char); // error, no matching template template<> auto g(double); // OK, forward declaration with unknown return type template<typename T> T g(T t) { return t; } // OK, not equivalent to #1 template char g(char); // OK, now there is a matching template template auto g(float); // still matches #1 // void h() { return g(42); } // error, ambiguous Explicit instantiation declarations do not themselves instantiate function templates that use return type deduction. template<typename T> auto f(T t) { return t; } extern template auto f(int); // does not instantiate f<int> int (*p)(int) = f; // instantiates f<int> to determine its return type, // but an explicit instantiation definition // is still required somewhere in the program

(since C++14)

参数表

参数列表确定在调用函数时可以指定的参数。是一个逗号分隔的列表。参数声明,其中每一个都具有以下语法。

attr(optional) decl-specifier-seq declarator

(1)

?

attr(optional) decl-specifier-seq declarator = initializer

(2)

?

attr(optional) decl-specifier-seq abstract-declarator(optional)

(3)

?

attr(optional) decl-specifier-seq abstract-declarator(optional) = initializer

(4)

?

...

(5)

?

void

(6)

?

1%29声明指定的%28形式%29参数。有关decl-说明符-seq和声明符的含义,请参见声明...

二次

代码语言:javascript
复制
int f(int a, int *p, int (*(*x)(double))[3]);

二次

2%29标记命名%28形式的%29参数,参数为默认值...

二次

代码语言:javascript
复制
int f(int a = 7, int *p = nullptr, int (*(*x)(double))[3] = nullptr);

二次

3%29声明一个未命名的参数

二次

代码语言:javascript
复制
int f(int, int *, int (*(*)(double))[3]);

二次

4%29使用默认值

二次

代码语言:javascript
复制
int f(int = 7, int * = nullptr, int (*(*)(double))[3] = nullptr);

二次

5%29变分函数,则只能作为参数列表中的最后一个参数出现。

二次

代码语言:javascript
复制
int printf(const char* fmt, ...);

二次

6%29表示函数不接受参数,它是空参数列表的确切同义词:int f(void);int f();声明相同的函数。注意,类型void%28可能是cv-限定%29不能在参数列表中使用,否则:int f(void, int);int f(const void);虽然派生类型是错误%28,如void*可以使用%29。在模板中,只有非依赖的空洞类型才能使用%28a函数,其中包含一个类型的参数。T如果实例化,则不会成为无参数函数。T = void%29%28自C++11%29

虽然decl-说明符-seq意味着可以存在说明符除类型说明符外,唯一允许的其他说明符是register以及auto%28,直到C++11%29,而且几乎没有任何效果。

If any of the function parameters uses a placeholder (either auto or a constrained type), the function declaration is instead an abbreviated function template declaration: void f(auto (auto::*)(auto)); // #1 template<typename T, typename U, typename V> void f(T (U::*)(V)); // same as #1 void g1(const C1*, C2&); // #2 (assuming C1 and C2 are concepts template<C1 T, C2 U> void g1(const T*, U&); // same as #2

(concepts TS)

函数声明中声明的参数名称通常仅用于自记录目的。它们使用%28,但在函数定义中仍然是可选的%29。

参数列表中每个函数参数的类型是根据以下规则确定的:

1%29首先,decl-说明符-seq和声明器合并在一起,如下所示声明以确定类型。

2%29如果类型是“T数组”或“未知T界数组”,则将其替换为“指向T的指针”类型

3%29如果该类型是函数类型F,则将其替换为“指向F的指针”类型。

4%29顶级cv限定符从参数类型%28中删除。调整只影响函数类型,但%27T修改参数的属性:int f(const int p, decltype(p)*);int f(int, const int*);声明相同的函数%29

由于这些规则,下面的函数声明声明完全相同的函数:

二次

代码语言:javascript
复制
int f(char s[3]);
int f(char[]);
int f(char* s);
int f(char* const);
int f(char* volatile s);

二次

以下声明还声明了完全相同的函数。

二次

代码语言:javascript
复制
int f(int());
int f(int (*g)());

二次

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

(until C++14)

省略号参数之前的逗号,指示各种论点是可选的,即使它在省略号后面指示参数包扩展,因此以下函数模板完全相同:

二次

代码语言:javascript
复制
template<typename ...Args> void f(Args..., ...);
template<typename ...Args> void f(Args... ...);
template<typename ...Args> void f(Args......);

二次

使用此类声明的一个示例是std::is_function...

功能定义

非成员函数定义可能出现在命名空间范围内--只有%28--没有嵌套函数%29。阿成员函数定义也可以出现在类定义它们有以下语法:

attr(optional) decl-specifier-seq(optional) declarator virt-specifier-seq(optional) function-body

?

?

其中功能体是下列之一。

ctor-initializer(optional) compound-statement

(1)

?

function-try-block

(2)

?

= delete ;

(3)

(since C++11)

= default ;

(4)

(since C++11)

1%29正则功能体

2%29功能试块%28,它是一个常规函数体,封装在TRY/CATCH块%29中。

3%29显式删除函数定义

4%29显式默认函数定义,仅允许特殊成员函数

attr(C++11)

-

optional list of attributes. These attributes are combined with the attributes after the identifier in the declarator (see top of this page), if any.

decl-specifier-seq

-

the return type with specifiers, as in the declaration grammar

declarator

-

function declarator, same as in the function declaration grammar above

virt-specifier-seq(C++11)

-

override, final, or their combination in any order (only allowed for member functions)

ctor-initializer

-

member initializer list, only allowed in constructors

compound-statement

-

the brace-enclosed sequence of statements that constututes the body of a function

二次

代码语言:javascript
复制
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 { ... }

二次

功能体是复合语句%28序列的零或多个语句被一对大括号%29包围,在进行函数调用时执行。

参数类型以及函数的返回类型不能为不完全类类型,除删除函数%28外,自C++11%29。完整性检查是在函数的上下文中进行的。体体,这允许成员函数若要返回定义它们的类%28或其包围类%29,即使在定义%28的点上它%27s不完整,它在函数体%29中也是完整的。

函数定义的声明器中声明的参数为范围内在身体里。如果函数体中没有使用参数,则不需要命名为%28 it%27s,足以使用抽象声明器%29。

二次

代码语言:javascript
复制
void print(int a, int) // second parameter is not used
{
    std::printf("a = %d\n",a);
}

二次

即使是高层简历-资格在函数声明中丢弃参数时,它们修改参数的类型,使其在函数的正文中可见:

二次

代码语言:javascript
复制
void f(const int n) // declares function of type void(int)
{
    // but in the body, the type of n is const int
}

二次

Deleted functions If, instead of a function body, the special syntax = delete?; is used, the function is defined as 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 unevaluated expression. However, implicit ODR-use of a non-pure virtual member function that happens to be deleted is allowed. If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected. struct sometype { void* operator new(std::size_t) = delete; void* operator new = delete; }; sometype* p = new sometype; // error, attempts to call deleted sometype::operator new The deleted definition of a function must be the first declaration in a translation unit: a previously-declared function cannot be redeclared as deleted: struct sometype { sometype(); }; sometype::sometype() = delete; // error: must be deleted on the first declaration __func__ Within the function body, the function-local predefined variable __func__ is defined as if by. static const char __func__[] = "function-name"; This variable has block scope and static storage duration: 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

(since C++11)

示例1:非会员函数

二次

代码语言:javascript
复制
#include <iostream>
#include <string>
 
// declaration in namespace(file) scope
// (the definition is provided later)
int f1();
 
// simple function with a default argument, returning nothing
void f0(const std::string& arg = "world")
{
    std::cout << "Hello, " << arg << '\n';
}
 
// function returning a pointer to f0
auto fp11() -> void(*)(const std::string&)
{
    return f0;
}
 
// function returning a pointer to f0, pre-C++11 style
void (*fp03())(const std::string&)
{
    return f0;
}
 
int main()
{
    f0();
    fp11()("test");
    fp03()("again");
    int f2(std::string); // declaration in function scope
    std::cout << f2("bad12") << '\n';
}
 
// simple non-member function returning int
int f1()
{
    return 42;
}
 
// 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;
}

二次

产出:

二次

代码语言:javascript
复制
Hello, world
Hello, test
Hello, again
stoi() failed!
0

二次

缺陷报告

以下行为更改缺陷报告追溯应用于先前发布的C++标准。

DR

Applied to

Behavior as published

Correct behavior

CWG 1394

c++11

deleted function could not return an incomplete type

incomplete return type allowed

CWG 577

c++11

dependent type void could be used to declare a no-parameter function

only non-dependent void is allowed

CWG 393

c++14

types that include pointers/references to array of unknown bound can't be parameters

such types are allowed

代码语言:txt
复制
 ? cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com