函数与默认参数

翻译整理自 cppreference - 函数。

1. 函数定义

int add(int a, int b) {
    return a + b;
}

声明与定义可分离:

// 声明(头文件)
int add(int a, int b);

// 定义(源文件)
int add(int a, int b) {
    return a + b;
}

2. 默认参数

void log(const std::string& msg, int level = 0);

log("info");          // 等价 log("info", 0)
log("err", 1);

默认参数必须在最右的形参;声明时只能写一次。

3. inline

inline int square(int x) { return x * x; }

inline 建议编译器内联展开;现代编译器也会自行决定。

4. constexpr

编译期可求值:

constexpr int fact(int n) {
    return n <= 1 ? 1 : n * fact(n - 1);
}

constexpr int x = fact(5);     // 120

5. 函数重载

同名不同签名:

int  abs(int x)  { return x < 0 ? -x : x; }
long abs(long x) { return x < 0 ? -x : x; }
double abs(double x) { return x < 0 ? -x : x; }

6. 引用参数

void swap(int& a, int& b) {
    int t = a; a = b; b = t;
}

int x = 1, y = 2;
swap(x, y);

const 引用避免拷贝:

void print(const std::string& s) {
    std::cout << s;
}

7. 移动语义

void take(std::string&& s) {
    std::string mine = std::move(s);
}

std::string s = "x";
take(std::move(s));

8. 变长参数

C++11 起:可变参数模板:

template <typename... Args>
void print(Args... args) {
    (std::cout << ... << args);   // C++17 fold expression
}

print(1, " ", 2.0, "\n");

<cstdarg> 提供 C 风格 va_list(保留,但不推荐)。

9. 函数指针与 lambda

int (*op)(int, int);

auto add = [](int a, int b) { return a + b; };
op = +add;          // lambda 转函数指针
op(1, 2);

std::function<int(int, int)> f = add;

lambda 形式

[capture](params) mutable -> return_type { body };

auto sq    = [](int x) { return x * x; };
int  base  = 10;
auto add_base = [base](int x) { return x + base; };    // 按值捕获
auto inc   = [&base]() { base++; };                     // 引用捕获
auto all   = [=]() { ... };                              // 按值捕获所有
auto allr  = [&]() { ... };                              // 引用捕获所有

10. std::function 与 std::bind

#include <functional>
std::function<int(int)> f = [](int x) { return x * 2; };

auto bound = std::bind(f, std::placeholders::_1);
bound(5);

11. 函数返回值优化

std::vector<int> makeVec() {
    std::vector<int> v(1000);
    return v;             // RVO,不拷贝
}

auto v = makeVec();

C++17 起保证复制消除。

小结

C++ 函数特性丰富:默认参数、重载、引用、移动、lambda、constexpr、模板,让函数式与命令式混合编程成为可能。