---
# System prepended metadata

title: 第六章 函式 練習

---

# 第六章 函式 練習

## 練習 6.1

參數和引數之間的差異為何？

解：

引數是函式呼叫的實際值，是參數的初始值

## 練習 6.2

指出下列函式何者是錯的，並描述原因，以及你會如何進行更正

```cpp
（a）int f() {
       string s;
       // ...
       return s;
     }
（b）f2(int i) { /* ... */
     }
（c）int calc(int v1, int v1) { /* ... */
     }
（d）double square(double x) return x *
```

解：

- （a）回傳型別應改為 string
- （b）應加上回傳型別 void
- （c）參數不可為同名
- （d）函式主體一定要加上大括號（curly braces）

## 練習 6.3

撰寫並測試你自己版本的 fact

解：

```cpp
#include <iostream>

using std::cerr;
using std::cout;
using std::endl;

int fact(int i) {
  if (i < 0)
    cerr << "Input cannot be a negative number.";
  return i > 1 ? i * fact(i - 1) : 1;
}

int main() {
  cout << fact(5) << endl;
  return 0;
}
```

## 練習 6.4

編寫一個與使用者互動的函式，請求輸入一個數字並產生該數字的階乘。從 main 呼叫此函式

```cpp
#include <iostream>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

int fact(int i) { return i > 1 ? i * fact(i - 1) : 1; }

void userInput() {
  int n;
  cout << "Enter a number within [1, 11):" << endl;
  while (cin >> n) {
    if (n < 1 || n > 10) {
      cout << "Out of range, please try again." << endl;
      continue;
    }
    cout << fact(n) << endl;
    cout << "Enter a number within [1, 11):" << endl;
  }
}

int main() {
  userInput();
  return 0;
}
```

## 練習 6.5

傳寫一個函式回傳其引數的絕對值（absolute value）

```cpp
#include <iostream>

using std::cout;
using std::endl;

int abs(int i) { return i > 0 ? i : -i; }

int main() {
  cout << abs(-5) << endl;
  return 0;
}
```

## 練習 6.6

解釋參數、區域變數，以及區域 static 變數之間的差異。各自給出一個函式為例

解：

參數定義在函式的參數列表裡面，而區域變數定義在程式主體裡面，區域靜態變數在程式第一次經過它的定義述句時被初始化，並且直到程式終止時才被摧毀

```cpp
#include <iostream>

using std::cout;
using std::endl;

int count_add(int n) {
  static int ctr = 0;
  ctr += n;
  return ctr;
}

int main() {
  for (int i = 0; i != 10; ++i)
    cout << count_add(i) << endl;
  return 0;
}
```

## 練習 6.7

撰寫一個會在它第一次被呼叫時回傳 0，然後之後每次被呼叫就依序產生對應數字的函式

解：

```cpp
#include <iostream>

using std::cout;
using std::endl;

int generate() {
  static int ctr = 0;
  return ctr++;
}

int main() {
  for (int i = 0; i != 10; ++i)
    cout << generate() << endl;
  return 0;
}
```

## 練習 6.8

撰寫一個名為 Chapter6.h 的標頭檔，其中含有你為 6.1 中的習題所寫的函式的宣告

解：

```cpp
// 使用練習 6.4 的程式
int fact(int i);
void userInput();
```

## 練習 6.9

寫出你自己版本的 fact.cc 和 factMain.cc 檔案。這些檔案應該引入你來自前一節習題的 Chapter6.h。使用這些檔案來這些檔案來了解你的編譯器如何支援個別編譯

解：

```cpp
// fact.cpp
#include "Chapter6.h"
#include <iostream>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

int fact(int i) { return i > 1 ? i * fact(i - 1) : 1; }

void userInput() {
  int n;
  cout << "Enter a number within [1, 11) :" << endl;
  while (cin >> n) {
    if (n < 1 || n > 10) {
      cout << "Out of range, please try again." << endl;
      continue;
    }
    cout << fact(n) << endl;
    cout << "Enter a number within [1, 11) :" << endl;
  }
}
```

```cpp
// factMain.cpp
#include "Chapter6.h"
#include <iostream>

int main() {
  cout << "5! is:" << fact(5) << endl;
  userInput();
}
```

編譯指令：g++ factMain.cpp fact.cpp -o main

## 練習 6.10

使用指標撰寫一個函式來將兩個 int 的值對調（swap）。呼叫此函式並印出對調後的值來測試之

解：

```cpp
#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;

void swap(int *n, int *m) {
  int tmp = *n;
  *n = *m;
  *m = tmp;
}

int main() {
  for (int n, m; cout << "Please Enter:\n", cin >> n >> m;) {
    swap(&n, &m);
    cout << n << " " << m << endl;
  }
  return 0;
}
```

## 練習 6.11

撰寫並測試接受一個參考的你自己版本的 reset

解：

```cpp
#include <iostream>

using std::cout;
using std::endl;

void reset(int &i) { i = 0; }

int main() {
  int i = 42;
  reset(i);
  cout << i << endl;
  return 0;
}
```

## 練習 6.12

改寫 6.2.1 中練習 6.10 的程式，使用參考而非指標來對調兩個 int 的值。你認為哪個版本比較容易使用，原因何在？

```cpp
#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;

void swap(int &n, int &m) {
  int temp = n;
  n = m;
  m = temp;
}

int main() {
  for (int n, m; cout << "Please Enter:\n", cin >> n >> m;) {
    swap(n, m);
    cout << n << " " << m << endl;
  }
  return 0;
}
```
參考更好用，呼叫的介面也更為簡潔

## 練習 6.13

假設 T 是一個型別的名稱，請解釋宣告 void f(T) 和宣告 void f(T&) 的函式之間的差異

解：

void f(T) 的參數是透過數值複製傳遞，在函式中的 T 參數是引數的拷貝，改變 T 不會影響到原來的引數
void f(&T) 的參數是透過參考傳遞，在函式中的 T 是引數的參考，改變 T 會影響到原來的引數

## 練習 6.14

給出例子說明何時一個參數應該是參考型別。也給出參數不應該是參考的一個例子

解：

例如交換兩個整數的函式，參數應該使用參考

```cpp
void swap(int &n, int &m) {
  int temp = n;
  n = m;
  m = temp;
}
```

當引數的值是右值時，參數不能為參考型別，否則導致編譯錯誤

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

int main() {
  int i = add(1, 2);
  return 0;
}
```

## 練習 6.15

解釋 find_char 的每個參數之型別背後的原因。特別是，為什麼 s 是對 const 的一個參考，但 occurs 卻是一個普通的參考？為甚麼這些參數是參考，但 char 參數 c 卻不是？如果我們讓 s 是一個普通的參考，可能會發生什麼事？如果讓 occurs 是對 const 的一個參考會怎麼樣呢？

解：
1. 因為 string 很長，使用引數可以避免拷貝
2. 而在函式中我們不希望改變 s 的內容，所以令 s 為常數
3. occurs 是要傳遞到函式外部的變數，所以使用參考，occurs 的值會改變，所以是普通參考
4. 我們只需要 c 的值，這個引數可能是右值（右值引數無法用於左值參考參數），因此 c 不使用參考型別
5. 如果 s 是普通參考，也可能會意外改變原來字串的內容
6. occurs 如果是常數參考，那麼就代表不能改變它原來的值，那也就失去意義了

## 練習 6.16

下列函式，雖然是合法的，但其用處比預期低。請找出並解除這個函式所受的限制

```cpp
bool is_empty(string& s) { return s.empty(); }
```

解：

侷限性在於常數字串與字串字面值無法作為該函式的引數，如果下面這要使用會是不合法的：

```cpp
const string str;
bool flag = is_empty(str); // 非法
bool flag = is_empty("hello"); // 非法
```

所以要將這個函式的參數定義為常數參考

```cpp
bool is_empty(const string& s) { return s.empty(); }
```

## 練習 6.17

寫一個函式來判斷一個 string 是否含有任何大寫字母。寫一個函式來將一個 string 全部變為小寫。你在這些函式中使用的參數有相同的型別嗎？若是，為甚麼呢？若非，為何沒有？

解：

兩個函式的參考不一樣。第一個函式使用常數參考，第二個函式使用普通參考

```cpp
// hasUpper
#include <iostream>
#include <string>

using std::cin;
using std::string;
using std::cout using std::boolalpha

    bool
    hasUpper(const string &s) {
  bool check = false;
  for (const char c : s) {
    check = isupper(c);
    if (check)
      return check;
  }
  return check;
}

int main() {

  string input;
  cout << "Please enter a string:";
  cin >> input;
  cout << boolalpha << hasUpper(input);
}
```
```cpp
// strToLower
#include <iostream>
#include <string>

using std::cin;
using std::string;
using std::cout using std::boolalpha

    std::string &
    strToLower(std::string &s) {
  for (char &c : s)
    c = tolower(c);
  return s;
}

int main() {
  std::string input;
  std::cout << "Please enter a string:";
  std::cin >> input;
  std::cout << strToLower(input);
}
```
## 練習 6.18

為下列每個函式撰寫宣告。當你編寫這些宣告時，使用函式名稱來表明函式所做的事

- （a）一個名為 compare 的函式，它會回傳一個 bool 並有兩個參數，這兩個參數都是對名為 matrix 的類別的參考
- （b）一個名為 change_val 的函式，它會回傳一個 vector\<int> 迭代器，並接受兩個參數：其一是一個 int，而另一個是某個 vector<int> 的迭代器

解：

```cpp
（a）bool compare(matrix &m1, matrix &m2);
（b）vector<int>::iterator change_val(int num, vector<int>::iterator iter);
```

## 練習 6.19

給定下列宣告，判斷那些呼叫是合法的，而哪些是非法的。對於那些非法的呼叫，請解釋不合法的原因

```cpp
double calc(double);
int count(const string &, char);
int sum(vector<int>::iterator, vector<int>::iterator, int);
vector<int> vec(10);
（a）calc(23.4, 55.1);
（b）count("abcda",'a');
（c）calc(66);
（d）sum(vec.begin(), vec.end(), 3.8);
```

解：

- （a）不合法，calc 只有一個參數
- （b）合法
- （c）合法
- （d）合法

## 練習 6.20

什麼時候參考參數應該是對 const 的參考呢？如果我們在一個參數可以對 const 的參考之時讓它是一個普通的參考，那會發生什麼事呢？

解：

應盡量將參考參數設為常數，除非有明確的目的是為了改變這個參考參數
如果參數應該是常數參考，而我們將其設為了普通參考，那麼常數引數或字面值將無法用於普通參考參數

## 練習 6.21

撰寫一個函式，接受一個 int 和對 int 的一個指標，並回傳所接受的 int 值和指標所指的值之中比較大的那一個。你應該為這個指標使用什麼型別呢？

解：

```cpp
#include <iostream>

using std::cout;

int larger_one(const int i, const int *const p) { return (i > *p) ? i : *p; }

int main() {
  int i = 6;
  cout << larger_one(7, &i);
  return 0;
}
```

應為 const int* const 型別

## 練習 6.22

寫一個函式來對調兩個 int 指標

解：

```cpp
#include <iostream>
#include <string>

using std::cout;
using std::endl;

void swap(int *&n, int *&m) {
  int *tmp = n;
  n = m;
  m = tmp;
}

int main() {
  int i = 30, j = 90;
  int *n = &i, *m = &j;
  swap(n, m);
  cout << *n << " " << *m << endl;
  return 0;
}
```

## 練習 6.23

為本節所呈現的那些 print 函式寫出你自己的版本。呼叫那些函式中的每一個來印出定義如下的 i 與 j：

```cpp
int i = 0, j[2] = { 0, 1 };
```

解：

```cpp
#include <iostream>

using std::begin;
using std::cout;
using std::end;
using std::endl;

void print(const int *pi) {
  if (pi)
    cout << *pi << endl;
}

void print(const int *beg, const int *end) {
  while (beg != end)
    cout << *beg++ << endl;
}

void print(const int ia[], size_t size) {
  for (size_t i = 0; i != size; ++i) {
    cout << ia[i] << endl;
  }
}

void print(int (&arr)[2]) {
  for (auto i : arr)
    cout << i << endl;
}

int main() {
  int i = 0, j[2] = {0, 1};
  print(&i);
  print(begin(j), end(j));
  print(j, end(j) - begin(j));
  print(j);
  return 0;
}
```

## 練習 6.24

解釋下列函式的行為。如果程式碼中有問題，請解釋問題為何，以及你會如何修正它們

```cpp
void print(const int ia[10]) {
  for (size_t i = 0; i != 10; ++i)
    cout << ia[i] << endl;
}
```

解：

當陣列作為引數的時候，會自動轉換為指向第一個元素的指標，因此函式的參數接受的是一個指標，實際上，以陣列作為參數都會被轉為指向元素型別的指標，而函式則會被轉為指向函式的指標

如果要讓這個程式碼可以執行（不更改也可以執行），可將參數改為陣列的參考

```cpp
void print(const int (&ia)[10]) {
  for (size_t i = 0; i != 10; ++i)
    cout << ia[i] << endl;
}
```

## 練習 6.25

撰寫接受兩個引數的一個 main 函式。串接所提供的引數，並印出所產生的 string

## 練習 6.26

寫一個程式接受在本節中呈現的那些選項。印出傳入 main 的引數之值

解：

```cpp
#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

int main(int argc, char **argv) {
  string str;
  for (int i = 1; i != argc; ++i)
    str += string(argv[i]) + " ";
  cout << str << endl;
  return 0;
}
```

## 練習 6.27

撰寫一個函式，接受一個 initializer_list\<int> 並產生該串列中元素的總和

解：

```cpp
#include <initializer_list>
#include <iostream>

using std::cout;
using std::endl;
using std::initializer_list;

int sum(initializer_list<int> const &il) {
  int sum = 0;
  for (auto i : il)
    sum += i;
  return sum;
}

int main(void) {
  auto il = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  cout << sum(il) << endl;
  return 0;
}
```

## 練習 6.28

在具有 ErrCode 參數的那第二個版本的 error_msg 中，for 迴圈中的 elem 之型別為何？

解：

elem 是 const string& 型別

## 練習 6.29

當你在一個範圍 for 中使用一個 initializer_list，你會使用一個參考作為迴圈的控制變數嗎？若是，為甚麼呢？如果不是，為何不呢？

解：

會使用常數參考型別，因為 initializer_list 物件中的元素都是常數，我們無法修改 initilizer_list 物件中元素的值

## 練習 6.30

編譯前面所呈現的 str_subrange 版本，看看你的編譯器會如何處理我們提過的那些錯誤

解：

```
main.cpp:4:5: error: return-statement with no value, in function returning ‘bool’ [-fpermissive]
```

## 練習 6.31

何時回傳一個參考是有效的呢？那麼對 const 的參考呢？

解：

當回傳的參考引用的物件是區域變數時，回傳的參考會是無效的（也被稱為 dangling），當我們希望回傳的物件被修改時，回傳常數參考是無效的

## 練習 6.32

指出下列的函式是否合法。若是，解釋為何如此；如果不是，更正所有的錯誤並解釋之

```cpp
int &get(int *array, int index) { return array[index]; }
int main() {
  int ia[10];
  for (int i = 0; i != 10; ++i)
    get(ia, i) = i;
}
```

解：

合法，get 函式根據索引取得陣列中的元素的參考

## 練習 6.33

寫一個遞迴函式印出一個 vector 的內容

解：

```cpp
#include <iostream>
#include <vector>

using std::vector;
using std::cout;
using Iter = vector<int>::const_iterator;

void print(Iter first, Iter last)
{
    if (first != last)
    {
        cout << *first << " ";
        print(++first, last);
    }
}

int main()
{
    vector<int> vec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    print(vec.cbegin(), vec.cend());
    return 0;
}
```

## 練習 6.34

如果 factorial 中的停止條件是 if (val != 0) 會發生什麼事？

解：

如果 val 為正數，以結果來看並無區別，只是多乘了 1
如果 val 為負數，那麼遞迴永遠都不會結束

## 練習 6.35

對 factorial 的呼叫中，為甚麼我們傳入 val - 1 而非 val--？

解：

如果傳入的值是 val--，那麼將會永遠傳入相同的值來呼叫該函式，則遞迴永遠都不會結束，可改為 --val

## 練習 6.36

宣告一個會回傳一個參考的函式，該參考指涉有十個 string 的一個陣列，而且不使用尾端回傳、decltype 或型別別名

解：

```cpp
string (&fun())[10];
```

## 練習 6.37

為前一個練習中的函式撰寫三個額外的宣告。其中一個應該使用型別別名，一個使用尾端回傳，而第三個則使用 decltype。你喜歡哪個形式？為甚麼呢？

解：

```cpp
typedef string str_arr[10];
str_arr& fun();

auto fun()->string(&)[10];

string s[10];
decltype(s)& fun();
```
個人認為使用尾端回傳最好，較為簡潔且只需要一行程式碼

## 練習 6.38

修改 arrPtr 函式，改回傳對陣列的一個參考

解：

```cpp
decltype(odd) &arrPtr(int i) { return (i % 2) ? odd : even; }
```

## 練習 6.39

解釋下列每組宣告中第二個宣告的效果。指出何者是非法的，如果有的話

```cpp
（a）int calc(int, int);
	 int calc(const int, const int);
（b）int get();
	 double get();
（c）int *reset(int *);
	 double *reset(double *);
```

解：

- （a）非法，因為頂層 const 不影響傳入函式的物件，所以無法區分第一個宣告與第二個宣告
- （b）非法，對於重載的函式中，它們應該只有參數的數量和參數的型別不同，回傳值與重載無關
- （c）合法

## 練習 6.40

下列哪個宣告是錯的？為甚麼呢？

```cpp
（a）int ff(int a, int b = 0, int c = 0);
（b）char *init(int ht = 24, int wd, char bckgrnd);
```

解：

- （a）正確
- （b）錯誤，一旦某個參數被賦予了默認值，那麼它之後的參數都必須要有默認值

## 練習 6.41

下列哪個呼叫是非法的呢？為甚麼呢？如果有的話，哪個是合法的，但不太可能是程式設計師所期望的？為甚麼呢？

```cpp
char *init(int ht, int wd = 80, char bckgrnd = ' ');
（a）init();
（b）init(24,10);
（c）init(14,'*');
```

解：

- （a）非法，第一個參數沒有默認值，因此最少需要一個引數
- （b）合法
- （c）合法，但使用方式不正確，字元 * 被轉換成 int 傳入到了第二個參數，而不是第三個參數

## 練習 6.42

賦予 make_plural（6.3.2）的第二個參數一個 's' 的預設引數。印出字詞 success 和 failure 的單數與複數版本來測試你的程式

解：

```cpp
#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

string make_plural(size_t ctr, const string &word, const string &ending = "s") {
  return (ctr > 1) ? word + ending : word;
}

int main() {
  cout << "single: " << make_plural(1, "success", "es") << " "
       << make_plural(1, "failure") << endl;
  cout << "plural: " << make_plural(2, "success", "es") << " "
       << make_plural(2, "failure") << endl;
  return 0;
}
```

## 練習 6.43

你會將下列哪個宣告和定義放在一個標頭中？或放在源碼檔中？請解釋原因

```cpp
（a）inline bool eq(const BigInt&, const BigInt&) {...}
（b）void putValues(int *arr, int size);
```

解：

全部都放進標頭中，因為（a）是 inline 函式，（b）是函式宣告

## 練習 6.44

將 6.2.2 的 isShorter 函式改寫為 inline

解：

```cpp
inline bool is_shorter(const string &str1, const string &str2) {
  return str1.size() < str2.size();
}
```

## 練習 6.45

重新檢視你為前面的練習所寫的程式，判斷它們是否應該被定義為 inline。如果是，就那麼做。若非，請解釋它們為何不應該是 inline

解：

一般來說，inline 應用於較簡短、流程直接、頻繁呼叫的函式上

## 練習 6.46

有可能將 isShorter 定義為一個 constexpr 嗎？若是，就那麼做。如果沒辦法，請解釋原因

解：

不能，因為 string.size() 並不是 constexpr 函式，因此 s1.size() == s2.size() 並不是一個 constant expression

## 練習 6.47

修改你在 6.3.2 的練習中寫的那個以遞迴印出一個 vector 內容的程式，讓它能夠條件式地印出其執行相關的資訊。舉例來說，你可能會在每次呼叫印出 vector 的大小，編譯並執行該程式，先開啟除錯來執行，然後關閉除錯再次執行

解：

```cpp
#include<iostream>
#include <vector>

using std::vector;
using std::cout;
using std::endl;

void printVec(vector<int> &vec) {
#ifndef NDEBUG
  cout << "Vector size: " << vec.size() << endl;
#endif
  if (!vec.empty()) {
    auto tmp = vec.back();
    vec.pop_back();
    printVec(vec);
    cout << tmp << " ";
  }
}

int main() {
  vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
  printVec(vec);
  cout << endl;
  return 0;
}
```

## 練習 6.48

解釋這個迴圈所做的事，以及這是否為 assert 的良好用法：

```cpp
string s;
while (cin >> s && s != sought) { } // 空的主體
assert(cin);
```

解：

不合理，從這個程式的意圖來看，應該改為：

```cpp
assert(s == sought);
```

## 練習 6.49

候選函式是甚麼？合用函式是什麼？

解：

候選函式：與被呼叫的函式同名，並且其宣告在呼叫的地方是可見的
合用函式：參數與引數的數量相等，並且每個引數型別與對應的參數型別相同或者能轉換成參數的型別

## 練習 6.50

給定前面的 f 宣告，為下列每個呼叫列出合用的函式。指出哪個函式是最佳匹配，哪個呼叫因為沒有匹配或歧義而是非法的

```cpp
（a）f(2.56, 42)
（b）f(42)
（c）f(42, 0)
（d）f(2.56, 3.14)
```

解：

- （a）void f(int, int); 和 void f(double, double = 3.14); 都是合用的函式，但呼叫有歧異而不合法
- （b）void f(int); 是合用的函式，且呼叫合法
- （c）void f(int, int); 和 void f(double, double = 3.14); 都是合用的函式，而 void f(int, int); 是最佳匹配
- （d）void f(int, int); 和 void f(double, double = 3.14); 是可行函式，void f(double, double = 3.14); 是最佳匹配

## 練習 6.51

寫出 f 的四個版本。每個函式都應該印出一個足以區別的訊息。檢查你在前一個練習的答案。如果你的答案是錯的，就研讀這一節，直到你了解為何答案是錯的為止

解：

```cpp
#include <iostream>

using std::cout;
using std::endl;

void f()
{
    cout << "f()" << endl;
}

void f(int)
{
    cout << "f(int)" << endl;
}

void f(int, int)
{
    cout << "f(int, int)" << endl;
}

void f(double, double)
{
    cout << "f(double, double)" << endl;
}

int main()
{
    //f(2.56, 42); // error: 'f' is ambiguous.
    f(42);
    f(42, 0);
    f(2.56, 3.14);
    return 0;
}
```

## 練習 6.52

給定下列宣告

```cpp
void manip(int ,int);
double dobj;
```

下列呼叫中每個轉換的排位（6.6.1）為何？

```cpp
（a）manip('a', 'z');
（b）manip(55.4, dobj);
```

解：

- （a）第三級，透過型別提升所達成的匹配
- （b）第四級，透過算術型別轉換所達成的匹配

## 練習 6.53

說明下列宣告組合中第二個宣告的效果。如果有的話，指出哪個是非法的

```cpp
（a）int calc(int&, int&);
	 int calc(const int&, const int&);
（b）int calc(char*, char*);
	 int calc(const char*, const char*);
（c）int calc(char*, char*);
	 int calc(char* const, char* const);
```

解：

- （a）：合法，為函式多載，代表的函式是不相同的
- （a）：合法，為函式多載，代表的函式是不相同的
- （c）：非法，函式參數列中的頂層 const 在不影響函式匹配

## 練習 6.54

為一個函式撰寫宣告，它有兩個 int 參數，並回傳一個 int，然後再宣告一個 vector，其元素具有這種函式指標型別

解：

```cpp
int func(int, int);
vector<decltype(func)*> v;
```

## 練習 6.55

寫出四個函式，為每兩個 int 值進行加、減、乘和除。將這些函式的指標儲存到你為前一個練習所寫的 vector

解：

```cpp
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }

v.push_back(add);
v.push_back(subtract);
v.push_back(multiply);
v.push_back(divide);
```

## 練習 6.56

呼叫那個 vector 中的每個元素，並印出它們的結果

解：

```cpp
std::vector<decltype(func) *> vec{add, subtract, multiply, divide};
for (auto f : vec)
  std::cout << f(2, 2) << std::endl;
```