为什么在使用#define声明int的vector的vector时没有抛出错误

Why no error is thrown on declaring vector of vector of int using #define

本文关键字:vector 出错 错误 #define 声明 int 为什么      更新时间:2023-10-16
#include <bits/stdc++.h>
using namespace std;
#define vi vector<int>
#define vvi vector<vi>
int main() {
vi v(10, -1);
vvi vv(10, v);
for(int i=0; i<vv.size(); i++){
for(int j=0; j<vv[i].size(); j++){
cout << vv[i][j] << " ";
}
cout << endl;
}
}

当我编译上面的代码时,没有任何错误报告,并且运行良好(见此)。但是,当我使用vector < vector < int>>声明int的向量的向量时,会发生错误,因为我没有在直角括号之间放置空格。那么,当#define所做的只是用vector<int>替换vi,用vector< vector< int>>替换vvi时,为什么在第一种情况下没有报告错误呢?

#define方法没有得到错误的原因是预处理器正在智能地插入中断。如果您只通过预处理器阶段(例如gcc -E)传递该代码,您将看到类似以下内容:

int main() {
vector<int> v(10,-1);
vector<vector<int> > vv(10,v);           // <<-- see space here.
for(int i=0; i<vv.size(); i++){
for(int j=0; j<vv[i].size(); j++){
cout << vv[i][j] << " ";
}
cout << endl;
}
return 0;
}

发生这种情况的原因与ISO C++标准规定的翻译阶段有关。

C++11(a)的第2.2节指出有九个翻译阶段。阶段3是将源文件拆分为预处理令牌和空白空间。

重要的是标记化,因此vector<vi>是预处理标记{vector, <, vi, >}的集合,它是而不是宏替换部分中给出的简单文本。而简单化文本替换:

#define vi vector<int>
#define vvi vector<vi>
vvi xyzzy;

将导致:

vector<vector<int>> xyzzy;

实际上最终得到的是预处理令牌集:

{vector, <, vector, <, int, >, >, WHITESPACE, xyzzy, ;}

然后,在第7阶段,标准规定:

每个预处理令牌都转换为一个令牌。

因此,没有将两个>令牌重组为一个令牌,尽管对源代码的简单读取可能表明这一点。


(a)请记住,尽管我引用了标准的C++11部分以确保答案是最新的,但这个特定的问题是C++03问题。C++11实际上修复了解析器,使得多个>字符将关闭一个合理的模板参数列表(C++03总是将其视为右移运算符)。

C++11 14.2, section 3指定:

解析模板参数列表时,将第一个非嵌套的>作为结束分隔符,而不是大于运算符。类似地,第一个非嵌套的>>被视为两个连续但不同的>令牌。。。

出现此错误是因为在C++03中,双尖括号被解释为右移运算符>>。在C++11中,该语言被更改为关闭模板参数,因此它应该在C++11模式下编译而不会出错。您可以通过在闭合尖括号之间留出一个空格来解决此问题,例如vector<vector<int> >

另外,不要使用#define来定义这样的类型别名;请改用typedef,因为这正是它的用途。