C++ Primer: Functions

C++ Primer: Functions

本篇博客主要记录《C++ Primer》一书的第六章 Functions 的相关知识点

  1. Arugment Passing

    在定义函数时,如果参数不同是可以重载函数的。但是如果参数时指针/数组,就会容易出现一些小问题。

    1
    2
    3
    void print(const int*) {}
    /* void print(const int[]) {} */
    /* void print(const int[10]) {} */

    比如以上的代码,无论是数组,还是指针参数,其实在处理的时候都会被当成指针来处理,也就是上面的三个看起来参数不同的函数,其实是同一个函数定义。如果取消掉注释,编译的时候是会报重定义的错误的。

    那么如果参数不是数组指针,而是数组引用呢?

    1
    2
    3
    /* void print(int (&arr)[]) {} */
    void print(int (&arr)[2]) {}
    void print(int (&arr)[10]) {}

    上面的函数定义其实并不会报重定义的错误,因为参数是不同的,是不同长度的数组引用。值得注意的是,由于是引用,如果不指定长度是会报错的。

    在调用上面定义的函数时,也需要注意,对于参数是长度为2的数组引用,传入的数组必须是长度为2的,同样,对于参数是长度为10的数组引用,传入的数组也必须是长度为10的数组。

  2. varying parameters

    • C 的方法(不建议使用)

      在C中可以使用 ... 来代表可变长参数来定义函数。这个 ... 实际上利用了 C 库的 varargs

    • initializer_list 列表参数方法

      定义函数时将可变长的部分用 initializer_list<type> xxx 来定义,在使用的时候,通过传入 {xxx, xxx, xxx} 来传递可变长参数。值得注意的是,这个initializer_list 中传递的参数都是 const 的,是不可以改变的,这一点和使用 vector 是不同的,也更加符合参数的语义。

      举例来说,使用方法大概如下

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      void error_msg(initializer_list<string> il) {
      for (auto& elem: il) {
      cout << elem << " ";
      }
      cout << endl;
      }

      int main() {
      error_msg({"This""is", "a", "test"});
      }
    • variadic template

  3. return type

    在 C/C++ 中,如果函数返回一个指向数组的指针,写法是比较奇怪的。

    1
    2
    3
    int (*func())[] {
    // ...
    }

    要避免这种不太容易识别的写法也是可以的。这本书里提到了很多方法,在 C++11 之前,可以使用 typedef 来定义类型别名,当然使用 using 也是可以的。

    1
    2
    3
    typedef int arrT[];
    using arrT = int[];
    arrT *func(int i);

    除此以外,还可以使用 trailing return type 的方式,就是在函数参数列表之后使用 -> 类型 的方式来表示返回类型。

    1
    auto func(int i) -> int (*)[];
  4. overloading

    定义重载函数必须保证参数数量或者参数类型不一样,否则会造成重定义。这里有个值得注意的地方,当参数被 const 修饰的时候,const 必须是 low-level consttop-level const 是会被忽略的,因此对于被 top-level const 修饰和未被修饰的参数重载函数会被认为是重定义。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    int func(int);
    int func(const int); // 重定义
    int func(int *);
    int func(int* const); // 重定义

    int func(int &);
    int func(const int &); // ok
    int func(int *);
    int func(const int*); // ok
  5. default arguments

    默认参数在进行赋值的时候,除了不能使用局部变量,其他表达式都能使用。

  6. inline

    inline 函数是程序员希望这个函数会被 compiler 展开,但是 compiler 并不会满足所有的 inline 请求,是否会进行转化还是要看 compiler 的。

  7. constexpr functions

评论