#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;
}
}
当我编译上面的代码时,没有报告错误,它运行正常(see this)。但是当我使用vector < vector < int>>
声明int向量的向量时,会发生错误,因为我没有在右尖括号之间放置空格。那么,为什么#define
所做的只是vi
与vector<int>
和vvi
与vector< vector< int>>
的匹配,在第一种情况下没有报告错误?
答案 0 :(得分:8)
您没有使用#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的第2.2节(a)指出有九个翻译阶段。第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
指定了:
解析模板参数列表时,第一个非嵌套
>
被视为结束分隔符,而不是大于运算符。同样,第一个非嵌套>>
被视为两个连续但不同的>
令牌......
答案 1 :(得分:1)
发生错误是因为在C ++ 03中,双尖括号被解释为右移位运算符>>
。在C ++ 11中,语言被改变,因此它被解释为关闭模板参数,因此它应该在C ++ 11模式下编译而没有错误。您可以通过在闭合尖括号之间放置一个空格来解决这个问题。 vector<vector<int> >
。
另外,不要使用#define
来定义类似别名;请改用typedef
,因为它正是它的目的。