为什么在使用#define声明int向量的向量时不会抛出错误

时间:2014-02-17 06:43:08

标签: c++ vector

#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所做的只是vivector<int>vvivector< vector< int>>的匹配,在第一种情况下没有报告错误?

2 个答案:

答案 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,因为它正是它的目的。