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

Nik*_*nka 2 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我编译上面的代码时,没有报告错误,它运行正常(见这个).但是当我声明int的向量向量使用vector < vector < int>>错误时,因为我没有在右尖括号之间放置一个空格.那么,为什么在第一种情况下没有报告错误,#define只需要替换viwith vector<int>vviwith 的出现vector< vector< int>>

pax*_*blo 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;
}
Run Code Online (Sandbox Code Playgroud)

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

C++ 11 (a)的 2.2节规定有九个翻译阶段.阶段3是将源文件拆分为预处理令牌和空白区域.

重要的是令牌化,因此这vector<vi>是一组预处理令牌{vector, <, vi, >},它不是宏替换部分中给出的简单文本.虽然简单的文字替换:

#define vi vector<int>
#define vvi vector<vi>
vvi xyzzy;
Run Code Online (Sandbox Code Playgroud)

会导致:

vector<vector<int>> xyzzy;
Run Code Online (Sandbox Code Playgroud)

居然结了是预处理标记集:

{vector, <, vector, <, int, >, >, WHITESPACE, xyzzy, ;}
Run Code Online (Sandbox Code Playgroud)

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

每个预处理令牌都转换为令牌.

因此,>尽管对源的简单读取可能表明这两个令牌没有重新组合成单个令牌.


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

C++11 14.2, section 3 指定:

解析模板参数列表时,第一个非嵌套>被视为结束分隔符而不是大于运算符.同样,第一个非嵌套>>被视为两个连续但不同的>标记......