第12章:functions

(1): 函数的声明:

在c++11新标准中,有两种函数声明的方式,第一种是返回类型放在函数名字的前面;第二种是返回类型放在函数参数列表的后面。例如这下面两种声明方式是等价的:

string to_string(int a); //c++老标准中的声明方式;
auto to_string(int a)->string;//c++11中新添加的声明方式;

对于第二种声明方式,放在函数名字前面的auto表明这个函数的返回类型是放在参数列表的后面的,不过在函数参数列表和返回类型中间有一个->。

虽然第二种函数声明能够用于任何函数,但我们一般把它用在返回类型依赖于参数的模板函数中。见下面例子:

template<class T,class U>
auto product(T i,U j) -> decltype(T{}*U{}) //decltype(T{}*U{})也可以写成decltype(i*j);
{
        return i*j;
}

(2):constexpr 函数

constexpr函数的概念:

一般来说,函数不能在编译时间被计算,因此不能用于常数表达式。但是通过指定一个函数为constexpr 函数,表明这个函数能够在编译时间被计算,能够用于常数表达式。如下面例子所示:

constexpr double square(double x) { return x*x; } //square函数为constexpr 函数,能够在编译时间被计算。

constexpr double y=square(9);  //OK!

同时也需要注意的是,和inline函数类似,constexpr函数必须要在所有源文件中有相同的定义,因此可以定义多次。

constexpr函数函数体语句限制:

在c++11新标准中constexpr函数只能仅仅由一个return 语句组成,不能有循环,也不能有局部变量。并且函数体语句也不能有负作用(比如试图给非局部变量赋值)。如下面例子所示:

int glob;
constexpr void bad1(int a) //error! constexpr函数要有return语句,不能为void。
{
    glob=a; //error: 存在着副作用(试图给函数内非局部变量赋值)
}

constexpr int bad2(int a)
{
    if(a>0) return a; //error: 存在着if statement;
    else
            return -a;
}

constexpr int bad3(int a)
{
    int sum=0  //error: 存在着局部变量;

    for(int i=0;i!=a;++i) sum+=i; //error:存在着循环语句

    return sum;
}  

从上面来看,感觉constexpr函数函数体语句有很多限制,但其可以用于条件语句和递归,如下面例子所示:

constexpr int good1(int i)
{
    return i>0?1:0; //Okay, 条件表达式能够存在
}

constexpr int good2(int n)
{
    return (n>1)?n*fac(n-1):1; //Okay, 递归和条件表达式被允许
}

虽然constexpr函数的函数体语句不能去更改一个非局部变量的值,但是可以引用非局部变量的值。如下面代码所示:

constexpr int high=3;
constexpr int check(int i)
{
    return i>=high?1:0; //okay! 
}
constexpr函数返回类型和参数

constexpr函数可以返回类型,也可以返回返回类型的引用和类型指针,如下面例子代码所示:

constexpr const int* addr(const int& r) {return &r;}

constexpr函数参数不仅可以值传递,也可以引用传递,但是正如我们说的,constexpr函数不能给非局部变量赋值,因此只能是const引用;如下面代码所示

constexpr int print(const int& x) { return x; }

(3):指向函数的指针:

一个对象有着内存地址,同理,一个函数也会被分配内存地址,因此我们能够用一个指针指向某个函数,正如我们用一个指针指向某个对象一样。但是有一点不同于对象的是,我们能够通过指向对象的指针来修改对象的的值,但是我们不能通过指向函数的指针来修改函数。一般我们是通过指向函数的指针来调用该函数。例子代码如下:

int print(int);  //假设存在着已经被定义的print函数。

int (*pf)(int); //将pf声明为指向函数的指针,它所指向的函数带有一个int形参,返回类型是int。(*pf)两侧的括号是必要的,int *pf (int) 这个是声明了一个pf函数,返回类型是int*!

pf=print; //将pf指向print函数;
pf=&print; //将pf指向print函数;
int (*pf)(int)=print; //将pf指向print函数;
int (*pf)(int)=&print; //将pf指向print函数;上述四种方式等价。

pf(3); //相当于调用print(3);

我们可以向一个函数传递函数指针参数,例子代码如下:

int fcn(int (*pf)(int),int i)//int (*pf)(int)是函数指针类型形参
{
    return pf();
}

fcn(print,3) //向fcn这个函数传递print函数地址

/* 如果觉得int (*pf)(int)写起来太麻烦了,我们可以使用using
   声明,定义同义*/
using P= int (*) (int) ;
P pf=print;
int fcn(P pf,int i) { return pf(); }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值