C++Primer第五版 第三章 课后习题答案

第三章

3.2

cin从标准输入中一次读入一个词
读取操作会自动忽略开头的空白,从一个真正的字符开始读取,直到遇到下一个空白。
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;//空字符串
    cout << "输入单词,不包含空格" << endl;
    while (cin >> s)
    {
        cout << s << endl;
    }
    return 0;
}
使用getline一次读入一整行,行的结束标志是回车符(换行符也被读进去了,但是不存入string中)
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string line;//空字符串
    cout << "输入单词,可以包含空格" << endl;
    while (getline(cin,line))
    {
        cout << line << endl;
    }
    return 0;
}

3.4

请添加图片描述
运算符:==, !=, <, <=, >, >=

  • 输入两个字符串进行比较,如果不相等则输出较大的字符串
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s1, s2;//空字符串
    cin >> s1 >> s2;
    if (s1 == s2)
    {
        cout << "两个字符串相等" << endl;
    }
    else {
        if (s1 > s2)
            cout << "较大的字符串是:" << s1;
        else
            cout << "较大的字符串是:" << s2;
    }
    return 0;
}
  • 比较长度,并输出长度较大的字符串
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s1, s2;//空字符串
    cin >> s1 >> s2;
    if (s1.size() == s2.size())
    {
        cout << "两个字符串等长" << endl;
    }
    else {
        if (s1.size() > s2.size())
            cout << "较长的字符串是:" << s1;
        else
            cout << "较长的字符串是:" << s2;
    }
    return 0;
}

3.5

  • 读取多个字符串并连接在一起,输出大字符串
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s, s1;//空字符串

    while (cin >> s1)
    {
        s += s1;
    }
    cout << s << endl;
    return 0;
}

死循环,需要输入ctrl+z来结束
可以采用如下的询问方式结束循环:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    char c = 'y';
    string s, s1;//空字符串
    
    while (cin >> s1)
    {
        s += s1;
        cout << "是否继续输入(y or n)" << endl;
        cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入下一个字符串" << endl;
        }
        else
            break;
    }
    cout <<"拼接后的字符串:"<< s << endl;
    return 0;
}

此时一次只能输入一个字符串,否则第二个字符串的第一个字符会成为c的输入

  • 连接字符串并且用空格分隔
    修改while循环,注意不能用cout<<" ",要把空格也接入字符串才能在最后输出有空格字符串
    while (cin >> s1)
    {
        if (!s.size())
            s += s1;
        else {
            s = s + " " + s1;
        }
        cout << "是否继续输入(y or n)" << endl;
        cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入下一个字符串" << endl;
        }
        else
            break;
    }

3.6

请添加图片描述
字符串的字符换为x,改变内容用引用。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;//空字符串
    cin >> s;
    cout << "输入的字符是:\t" << s << endl;
    for (auto& c : s)
    {
        c = 'x';
    }

    cout <<"改变后的字符串:\t"<< s << endl;
    return 0;
}

3.8

如果处理范围内的每一个元素,采取范围for更好。string可以用下标操作[i]。

3.9

使用下标操作前先确定不是空字符串。

3.10

  • 使用范围for逐个输出非标点符号
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;//空字符串
    cin >> s;
    cout << "输入的字符是:" << s << endl;
    for (auto& c : s)
    {
        if (ispunct(c))//如果该字符是标点符号
        {
            continue;
        }
        else {
            cout << c << endl;
        }
    }
    return 0;
}
  • 普通for通过下标访问,把非标点符号重新拼接新串
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s,s1;//空字符串
    cin >> s;
    cout << "输入的字符是:" << s << endl;
    int n = s.size();
    for (int i = 0; i < n-1; i++)
    {
        if (ispunct(s[i]))
        {
            continue;
        }
        else {
            s1 += s[i];
        }
    }
    cout << "删除标点符号的字符串是:" << s1 << endl;
    return 0;
}

3.11

	const string s = "Keep out!";
	for(auto &c : s){/*~*/}

s是一个常量字符串,c的推断类型是常量引用,即c绑定的对象值不能改变。

3.13

注意花括号和圆括号的区别

  • 使用=,即拷贝初始化时,只能提供一个初始值
  • 只有一个类内初始值,则只能使用拷贝初始化或者花括号的形式
  • 列表初始化必须使用花括号而不是圆括号

3.14

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    vector<int> vInt;
    int i;
    char c = 'y';
    while (cin >> i)
    {
        vInt.push_back(i);
        cout << "是否继续输入(y or n)" << endl;
        cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入整数" << endl;
        }
        else
            break;
    }

    for (auto v : vInt)//输出来验证
    {
        cout << v << " ";
    }
    cin.clear();
    return 0;
}

3.16

具体内容采用范围for输出,容量采用size函数即可。
size函数得到的是元素的个数。

3.17

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    vector<string> vStr;
    string s;
    char c = 'y';
    while (cin >> s)
    {
        vStr.push_back(s);
        for (auto& v : vStr[vStr.size()-1])
        {
            v = toupper(v);
        }
        cout << "是否继续输入(y or n)" << endl;
        cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入单词" << endl;
        }
        else
            break;
    }

    for (auto v : vStr)//输出来验证
    {
        cout << v << endl;
    }
    cin.clear();
    return 0;
}

3.20

  1. 输出相邻整数的和
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    vector<int> vInt;
    int i;
    char c = 'y';
    while (std::cin >> i)
    {
        vInt.push_back(i);
        cout << "是否继续输入(y or n)" << endl;
        std::cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入单词" << endl;
        }
        else
            break;
    }
    
    for (decltype(vInt.size()) i = 0; i < vInt.size() - 1; i++)
    {
        cout << vInt[i] + vInt[i + 1]<<" ";
    }
    std::cin.clear();
    return 0;
}
  1. 头尾相加然后输出,以此类推
    如果是奇数,会有一个数未被处理
#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    vector<int> vInt;
    int i;
    char c = 'y';
    while (std::cin >> i)
    {
        vInt.push_back(i);
        cout << "是否继续输入(y or n)" << endl;
        std::cin >> c;
        if (c == 'y' || c == 'Y')
        {
            cout << "继续输入单词" << endl;
        }
        else
            break;
    }

    for (decltype(vInt.size()) m = 0; m < vInt.size()/2 ; m++)
    {
        cout << vInt[m] + vInt[vInt.size()-1-m] << " ";
    }
    cout << endl;
    if (vInt.size() % 2 == 1)//奇数
    {
        cout << "共有奇数个元素,中间的数字是:" << vInt[(vInt.size()-1) / 2] << endl;
    }

    return 0;
}

3.23

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    vector<int> vInt;
    srand((unsigned)time(NULL));//生成随机数种子
    for (int i = 0; i < 10; i++)
    {
        vInt.push_back(rand() % 1000);//生成一个1000以内的随机数并添加给vInt
    }

    auto b = vInt.begin();
    auto e = vInt.end();
    if (b != e)
    {
        for (; b != e; ++b)
        {
            cout << *b << "\t";
            *b = 2 * (*b);
        }
    }
    cout << endl;

    for (auto a = vInt.begin(); a != vInt.end(); ++a)
    {
        cout << *a << "\t";
    }
    cout << endl;
    return 0;
}

3.26

  • C++没有定义迭代器的加法运算,两个迭代器相加是没有意义的。
  • 两个迭代器相减的结果是它们之间的距离,即运算符右侧的迭代器向前移动多少个元素以后可以得到左侧的迭代器。
  • 参与运算的迭代器必须指向同一个容器的元素或者尾后元素。

3.27

  • 数组的维度必须大于0并且是一个常量表达式。
  • 一个返回int的普通函数不能作为数组的维度,定义为constexpr才可以。
  • 对数组推断类型,auto返回指针,decltype返回由n个元素构成的数组。

3.28

对于内置类型,定义在所有函数值之外会默认初始化,定义在函数内会导致未定义。

3.29

字符数组可以用strlen函数获得字符串的长度。
其他数组必须用sizeof(array) / sizeof(array[0])来获得维度。

3.31

a[i] = i 即可

3.33

  • 定义在函数内部的整型数组不会执行默认初始化,不初始化scores则会含有未定义的值。

3.35

使用标准库函数begin和end

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    const int sz = 10;
    int a[sz], i = 0;
    for (i = 0; i < 10; i++)
    {
        a[i] = i;
    }
    int* p = begin(a);//int *p = &a[0], *a
    int* e = end(a);
    for (auto m = p; m != e; ++m)
    {
        *m = 0;
    }

    for (auto n : a)
    {
        cout << n;
    }
    cout << endl;
    return 0;
}

expression部分是一个用于表示一个序列的对象。

  • 注意for (auto n : a) { cout << n; } 此处用的是a,和n
    如果使用了begin(a),编译器会有如下报错。
    在这里插入图片描述
  • 同样,使用容器的时候其实也是。
     for (auto v : vStr)
    {
        cout << v << endl;
    }
    

3.36

先比较长度,长度不同一定不同,长度相等则注意比较元素即可。

3.37

strlen函数如果对一个不是以空字符作为结束的字符数组使用,将会产生未定义的结果,可能沿着该字符数组的位置一直向前寻找直到遇到空字符。
同样对于指向字符的指针使用while循环,只要指针所指的字符不是空字符,循环就会重复执行,以知在内存中该指针所在的位置之后挨个寻找空字符。

3.39

  • 标准库string类定义了关系运算符,可以直接用>,<,==等进行比较
  • 两个C字符串进行比较必须使用cstring头文件定义的strcmp函数
  • 对C风格字符串应用>,<,==等相当于直接比较指针,即首元素地址,是const char* 的值。
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    //对两个C风格字符串进行比较
    char str1[80], str2[80];
    cout << "请输入两个字符串" << endl;
    cin >> str1 >> str2;
    //利用cstring头文件定义的strcmp函数比较大小
    auto result = strcmp(str1, str2);
    switch (result)
    {
    case 1:
        cout << "第一个字符串大于第二个字符串" << endl;
        break;
    case -1:
        cout << "第一个字符串小于第二个字符串" << endl;
        break;
    case 0:
        cout << "第一个字符串等于第二个字符串" << endl;
        break;
    default:
        cout << "未定义的结果" << endl;
        break;
    }

    return 0;
}

3.40(有点问题,已经解决)

C++11 constexpr和const的区别详解

  • constexpr 是 C++ 11 标准新添加的关键字,在此之前(C++ 98/03标准)只有 const关键字,其在实际使用中经常会表现出两种不同的语义。
  • const int x”只是想强调 x 是一个只读的变量,其本质仍为变量,无法用来初始化 array 容器;
  • “constexpr int x”,表明 x 是一个只读变量的同时,x 还是一个值为 5的常量,所以可以用来初始化array 容器。
  • C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
  • “只读”和“不允许被修改”之间并没有必然的联系,如下:
	#include <iostream>
	using namespace std;
	
	int main()
	{
	    int a = 10;
	    const int & con_b = a;
	    cout << con_b << endl;
	
	    a = 20;
	    cout << con_b << endl;
	}

程序执行结果为10 20

  • 程序中用 const 修饰了 con_b 变量,表示该变量“只读”,即无法通过变量自身去修改自己的值。但这并不意味着 con_b 的值不能借助其它变量间接改变,通过改变 a 的值就可以使 con_b 的值发生变化。
  • 总的来说在 C++ 11 标准中,const 用于为修饰的变量添加“只读”属性;而 constexpr 关键字则用于指明其后是一个常量(或者常量表达式),编译器在编译程序时可以顺带将其结果计算出来,而无需等到程序运行阶段,这样的优化极大地提高了程序的执行效率。
  • 混用string对象和C风格字符串:

在这里插入图片描述
注意C风格字符串用花括号进行列表初始化的时候,如果不手动添加空字符,将不会以空字符结束。采用字符串字面值常量来初始化C风格字符串时则会默认在数组最后添加一个空字符。

  • 使用strlen做数组维度的报错情况,strlen是非constexpr函数,即便用constexpr修饰n也不可行,仍会出现如下报错。
    在这里插入图片描述
  • 使用const修饰n依然没用,问题出在strlen函数上,可能是因为str1/2的改变会造成strlen返回值的改变
    在这里插入图片描述
  • 不用strlen函数的便可以作为数组的维度
	#include <iostream>
	#include <cstring>
	using namespace std;
	
	int main()
	{
	    //定义两个字符数组,用字符串字面值初始化
	    char str1[] = "Welcome to ";
	    char str2[] = "C++ family!";
	
	    const decltype(strlen(str1)) n = 50;
	    //strlen返回长度时空字符不计算在内
	    char str[n];//存放前两个数组的连接结果
	    strcpy(str, str1);//第一个字符串拷贝到结果字符串
	    strcat(str, str2);//第二个字符串接到结果字符串中
	    cout << str << endl;
	
	    return 0;
	}
  • 但是会对函数strcat和strcpy报错如下:

在这里插入图片描述

  • 修改成如下(strcpy换成strcpt_s,strcat换成sytcat_s)便可以顺利编译通过:
  • strcpy_s(str, str1);//第一个字符串拷贝到结果字符串
    strcat_s(str, str2);//第二个字符串接到结果字符串中
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    //定义两个字符数组,用字符串字面值初始化
    char str1[] = "Welcome to ";
    char str2[] = "C++ family!";

    const decltype(strlen(str1)) n = 50;
    //strlen返回长度时空字符不计算在内
    char str[n];//存放前两个数组的连接结果
    strcpy_s(str, str1);//第一个字符串拷贝到结果字符串
    strcat_s(str, str2);//第二个字符串接到结果字符串中
    cout << str << endl;

    return 0;
}

3.41

简单操作:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //只需要指明要拷贝区域的首元素和尾后元素的地址,即可用数组初始化vector对象
    int arr[] = { 0,1,2,3,4,5 };
    vector<int> ivec(begin(arr), end(arr));
    for (auto v : ivec)
    {
        cout << v << " ";
    }
    cout << endl;
    return 0;
}

随机数操作:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //只需要指明要拷贝区域的首元素和尾后元素的地址,即可用数组初始化vector对象
    const int sz = 10;
    int a[sz];
    srand((unsigned) time (NULL));//生成随机数种子
    int arr[sz];
    for (auto& a : arr)
    {
        a = rand() % 100;//生成100内的随机数
        cout << a << "\t";
    }
    cout << endl;

    vector<int> ivec(begin(arr), end(arr));
    for (auto v : ivec)
    {
        cout << v << "\t";
    }
    cout << endl;
    return 0;
}

3.42

  • 不要对空的vector使用范围for遍历:编译器无法发现该错误
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //只需要指明要拷贝区域的首元素和尾后元素的地址,即可用数组初始化vector对象
    vector<int> vInt;
    srand((unsigned) time (NULL));//生成随机数种子
    cout << "vector内的对象是:" << endl;
    for (auto& a : vInt)
    {
        a = rand() % 100;//生成100内的随机数
        cout << a << "\t";
    }
    cout << endl;
    int const n = 10;
    int a[n];
    int* p = a;
    for (auto b = vInt.begin(); b != vInt.end(); ++b)
    {
        *p = *b;
        cout << *p << "\t";
        p++;
    }

    cout << endl;
    return 0;
}

在这里插入图片描述

  • 也不可以用下标为空vector赋值,会出现out of range的错误:
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //只需要指明要拷贝区域的首元素和尾后元素的地址,即可用数组初始化vector对象
    vector<int> vInt;
    const int sz = 10;//用于给空vector赋值,以及数组的初始大小
    srand((unsigned) time (NULL));//生成随机数种子
    cout << "vector内的对象是:" << endl;
    for (int i=0;i<sz ; i++)
    {
        vInt[i] = rand() % 100;//生成100内的随机数
        cout << vInt[i] << "\t";
    }
    cout << endl;
    int a[sz];
    int* p = a;
    for (auto b = vInt.begin(); b != vInt.end(); ++b)
    {
        *p = *b;
        cout << *p << "\t";
        p++;
    }

    cout << endl;
    return 0;
}

在这里插入图片描述

  • 以下为正确的代码:用pushback为vector赋值
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    //只需要指明要拷贝区域的首元素和尾后元素的地址,即可用数组初始化vector对象
    vector<int> vInt;
    const int sz = 10;//用于给空vector赋值,以及数组的初始大小
    srand((unsigned) time (NULL));//生成随机数种子
    cout << "vector内的对象是:" << endl;
    for (int i=0;i<sz ; i++)
    {
        vInt.push_back(rand() % 100);//生成100内的随机数
        cout << vInt[i] << "\t";
    }
    cout << endl;
    int a[sz];
    int* p = a;
    for (auto b = vInt.begin(); b != vInt.end(); ++b)
    {
        *p = *b;
        cout << *p << "\t";
        p++;
    }

    cout << endl;
    return 0;
}

3.43

使用三个版本的程序输出多维数组ia的元素,且直接写出数据类型:

  1. 范围for管理迭代过程
    可以用int把auto换掉,因为此处auto推断出的类型就是int
  • 使用范围for处理多维数组,除了最内层的循环,其他所有循环的控制变量都必须是引用类型,否则内层循环无法使用外层循环取到的值。
	for(auto& row:ia)
	{ 
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}
  • 直接将row绑定到ia的第二个4元素数组上:int (&row)[4] = ia[1];
  • 此时row是一个含有四个整数的数组的引用,即引用的是由4个int型的数组。并将其绑定到第二行。
	for(auto (&row)[4]:ia)
	{ 
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}
  1. 普通for和下标运算符
	cout << "利用普通for和下标运算符" << endl;
	for (int i = 0; i != 3; i++)
	{
		for (int j = 0; j != 4; j++)
		{
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
  1. 普通for和指针
  • 定义指向多维数组的指针时,不要忘记了多维数组实际上是数组的数组
    圆括号必不可少,否则int *p[4] = ia会变成整型指针的数组
	int ia[3][4];
	int (*p)[4] = ia;//p指向含有4个整数的数组
	p = &ia[2];//p指向ia的尾元素
	其使用方法如下:
	for (int (*p)[4] = ia; p != ia + 3; p++)
	{
		for (int* q = *p; q != *p + 4; q++)
		{
			cout << *q << " ";
		}
		cout << endl;
	}
	return 0;
  • 直接用auto或者decltype可以避免在数组前面加上指针类型
	for(auto p = ia; p != ia+3; ++p)
	{
		for(auto q = *p; q != *p+4; ++q)
		{
			cout << *q << "" ;
		}
		cout << endl;
	}
  • 还可以用标准库函数begin和end来代替
	for(auto p = begin(ia); p != end(ia); ++p)
	{
		for(auto q = begin(*p); q != end(*p); ++q)
		{
			cout << *q << "" ;
		}
		cout << endl;
	}

最后的总程序如下所示:

#include <iostream>
using namespace std;

int main()
{
	int ia[3][4] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
	cout << "利用范围for" << endl;
	for(int (&row)[4]:ia)
	{ 
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}

	cout << "利用普通for和下标运算符" << endl;
	for (int i = 0; i != 3; i++)
	{
		for (int j = 0; j != 4; j++)
		{
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
	
	cout << "利用普通for和指针:" << endl;
	for (int (*p)[4] = ia; p != ia + 3; p++)
	{
		for (int* q = *p; q != *p + 4; q++)
		{
			cout << *q << " ";
		}
		cout << endl;
	}
	return 0;
}

3.44

在这里插入图片描述
要事先知道类型,普通for部分不用做改变

#include <iostream>
using namespace std;
using int_array = int[4];
//typedef int int_array[4];

int main()
{
	int ia[3][4] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
	cout << "利用范围for" << endl;
	for(int_array &row:ia)//auto (&row)[4]
	{ 
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}

	cout << "利用普通for和下标运算符" << endl;
	for (int i = 0; i != 3; i++)
	{
		for (int j = 0; j != 4; j++)
		{
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
	
	cout << "利用普通for和指针:" << endl;
	for (int_array *p = ia; p != ia + 3; p++)//int (*p)[4] = ia
	{
		for (int* q = *p; q != *p + 4; q++)
		{
			cout << *q << " ";
		}
		cout << endl;
	}
	return 0;
}

3.45

注意for (int* q = *p; q != *p + 4; q++)
变成了for (auto q = *p; q != *p + 4; q++)
使用了auto就不用在自行指定指针类型了

#include <iostream>
using namespace std;

int main()
{
	int ia[3][4] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
	cout << "利用范围for" << endl;
	for(auto (&row)[4]:ia)
	{ 
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}

	cout << "利用普通for和下标运算符" << endl;
	for (auto i = 0; i != 3; i++)
	{
		for (int j = 0; j != 4; j++)
		{
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
	
	cout << "利用普通for和指针:" << endl;
	for (auto (*p)[4] = ia; p != ia + 3; p++)
	{
		for (auto q = *p; q != *p + 4; q++)
		{
			cout << *q << " ";
		}
		cout << endl;
	}
	return 0;
}

针对3.40的constexpr和常量表达式复习

(C++Primer 2.4.4)

1 :常量表达式(const expression)

  • 是指值不会改变并且在编译过程中就得到计算结果的表达式。
  • 字面值属于常量表达式;常量表达式初始化的const对象也是常量表达式。
  • 一个对象(或表达式)是不是常量表达式是由它的数据类型和初始值共同决定的。
	const int max = 20;//max是常量表达式
	const int limit = max + 1;//limit是常量表达式
	int size = 27;//size不是常量表达式
	const int sz = getsize();//不是常量表达式
	尽管sz本身是一个常量,但是具体值直到运行的时候才可以获取到

2 :constexpr变量

  • C++11新标准允许将变量声明为constexpr类型,便于由编译器来验证变量的值是否是一个常量表达式。
  • 声明为constexpr的变量一定是一个常量,且必须用常量表达式初始化。
	constexpr int max = 20;//20是常量表达式
	constexpr int limit = max + 1;//max+1是常量表达式
	constexpr int sz = getsize();
	//只有当getsize是一个constexpr函数的时候这个语句才正确
  • 对于语句constexpr int sz = getsize();,geisize不是constexpr函数,编译器会报错
  • 虽然不能用普通函数作为constexpr变量的初始值,但是正如6.5.2所介绍,新标准允许定义一种特殊的constexpr函数,这种函数足够简单到编译时就可以计算其结果,,此时便可以用constexpr函数去初始化constexpr变量了。
  • constexpr函数:是指能用于常量表达式的函数。
  • 定义constexpr函数与其他函数类似,但是有几项约定:函数返回类型和所有形参类型都是字面值类型;函数体中必须有且只有一条return语句。
  • 为了在编译过程中随时展开,constexpr函数被隐式地指定为了内联函数。
  • constexpr函数不一定返回常量表达式。
  • 一般来说如果认定变量是一个常量表达式,就把它声明成constexpr类型

3 :字面值类型

  • 算术类型、引用和指针都属于字面值类型,还有一些在7.5.6和19.3有所介绍。
  • 指针和引用都能定义成constexpr,但是初始值受到严格的限制。一个constexpr指针的初始值必须是nullptr 或者 0 或者 存储在某个固定地址中的对象。
  • 6.1.1提到,函数体内定义的变量一般来说并不是存放在固定地址中,相反,定义在所有函数体之外的对象的地址固定不变,可以用来初始化constexpr指针。6.1.1还提到的是函数可以定义一类有效范围超出函数本身的变量,同样可以拥有固定的地址,即局部静态对象(将局部变量定义成static类型),可以在第一次经过对象语句的时候初始化,直到程序终止才被销毁。

4 :指针和constexpr

  • 如果在constexpr声明中定义了一个指针,限定符constexpr仅仅对指针有效,与指针所指的对象无关。
	const int* p = nullptr;//p是一个指向整型常量的指针
	constexpr int* q = nullptr;//q是一个指向整数的常量指针
  • 原因在与constexpr将其定义的对象置为了顶层const(2.4.3),其定义的指针是常量指针,与其他指针一样可以指向常量也可以指向非常量。指向常量的时候加const修饰,作为底层const。
	int j = 0;
	const int i = 42;//i的类型是整型常量
	constexpr const int *p = &i;//p是常量指针,指向整型的常量i
	constexpr int *q = j;//q是常量指针,指向整数j
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值