1 原生的逗号操作符
- 逗号表达式用于将多个子表达式连接为一个表达式
- 逗号表达式的值为最后一个子表达式的值
- 逗号表达式中的前 N-1 个子表达式可以没有返回值
- 逗号表达式按照从左向右的顺序计算每个子表达式的值
// 27-1.cpp
#include<iostream>
using namespace std;
void func(int i)
{
cout << "func(int) : i = " << i << endl;
}
int main()
{
int a[3][3] = {
(0, 1, 2), // 这里是三个逗号表达式,不是大括号
(3, 4, 5),
(6, 7, 8)
};
int i = 0;
int j = 0;
while (i < 5)
func(i),
i++;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
(i, j) = 6; // 逗号表达式,返回值为最后一个子表达式
cout << "i = " << i << endl;
cout << "j = " << j << endl;
return 0;
}
- 第 10-14 行,初始化数组,使用的是逗号表达式,三个逗号表达式三个返回值,所以只初始化前三个元素,要想给9个元素全部初始化,应该使用大括号。
- 第 17-19 行,while 循环中是一个逗号表达式,每次循环 i 加1,不是死循环
- 第 28 行,(i, j) = 6; 返回逗号表达式的最后一个子表达式的值,所以这里是将 6 赋值给 j。
$ g++ 27-1.cpp -o 27-1
$ ./27-1
func(int) : i = 0
func(int) : i = 1
func(int) : i = 2
func(int) : i = 3
func(int) : i = 4
2 5 8
0 0 0
0 0 0
i = 5
j = 6
2 重载逗号操作符
- 在 C++ 中重载逗号表达式是合法的,使用全局函数进行重载
- 重载函数的参数必须有一个是类类型
- 重载函数的返回值类型是引用
// 27-2.cpp
#include<iostream>
using namespace std;
class Test
{
public:
Test(int i) : mValue(i) {}
int value() { return mValue; }
private:
int mValue;
};
Test& operator , (const Test& a, const Test& b)
{
return const_cast<Test&>(b);
}
Test func(Test& i)
{
cout << "func() : i = " << i.value() << endl;
return i;
}
int main()
{
Test t0(0);
Test t1(1);
Test tt = (func(t0), func(t1));
cout << "tt.value() = " << tt.value() << endl;
return 0;
}
我们重载了逗号表达式,将类的对象使用逗号表达式,结果会怎么样呢
编译运行:
$ g++ 27-2.cpp -o 27-2
$ ./27-2
func() : i = 1
func() : i = 0
tt.value() = 1
对于表达式 (func(t0), func(t1)); 编译器 先计算 func(t1) 后计算 func(t1),前面说的逗号表达式按照从左向右的顺序计算每个子表达式的值,这里不是这样的了,为什么呢?
原因我们在上一篇博客中已经讲解了,重载逗号运算符,本质上是函数调用
- C++通过函数调用扩展操作符的功能
- 进入函数体之前必须完成所有参数的计算
- 函数参数的计算次序是不定的
- 所以重载后无法严格从左向右计算表达式
我们将代码 27-2.cpp 中的第 12-15 行注释,也就是将重载的逗号表达式注释,再次编译运行:
$ g++ 27-2.cpp -o 27-2
$ ./27-2
func() : i = 0
func() : i = 1
tt.value() = 1
我们发现没有逗号操作符的重载,一样可以对类使用逗号操作符,并且严格按照从左向右的计算顺序。
所以,在工程中不要重载逗号操作符
3 小结
1、逗号表达式从左向右计算每个子表达式的值
2、逗号表达式的值为最后一个子表达式的值
3、不要重载逗号表达式