乐于分享
好东西不私藏

C++ 模板嵌套中的尖括号:从 > > 到 >> 的演进

C++ 模板嵌套中的尖括号:从 > > 到 >> 的演进

在 C++ 模板编程中,尖括号 < 和 > 用于指定模板参数。当模板嵌套使用时,例如 vector<list<int>>,编译器需要正确解析连续的两个 > 符号——它究竟是模板参数列表的结束符,还是右移运算符 >>

C++98/03 时代的规则:必须添加空格

在 C++98 和 C++03 标准中,词法分析器会将 >> 始终解释为右移运算符(或流提取运算符)。因此,写下 vector<list<int>> 会被解析为 (vector<list<int>) > 或者产生一个语法错误,因为 >> 被当作一个单独的记号,而不是两个独立的 >

解决方法:在两个 > 之间插入一个空格,写成 > >,强制编译器将它们视为两个独立的结束符。

// C++98 / C++03 合法写法
#include<vector>
#include<list>

intmain(){
std::vector<std::list<int> > vl;  // 注意 > > 之间的空格
// std::vector<std::list<int>> vl; // 错误!>> 被当作右移运算符
return0;
}

C++11 及之后的改进:放宽规则

C++11 标准对模板语法进行了精细化调整,规定在模板参数列表结束的上下文中,连续的 >> 会被正确解析为两个右尖括号,而不再与右移运算符混淆。这使得代码书写更自然、更符合直觉。

// C++11 及之后合法写法
#include<vector>
#include<list>

intmain(){
std::vector<std::list<int>> vl;  // 现在可以直接使用 >>
// 完全等价于旧式的 std::vector<std::list<int> > vl;
return0;
}

注意事项

  • 向后兼容:C++11 之后的编译器仍然接受带空格的 > > 写法,旧代码可以继续编译。
  • 右移运算符歧义消除:编译器会根据上下文判断 >> 的含义。如果 >> 出现在模板参数列表的结束位置,它会被解释为两个右尖括号;否则仍为右移运算符。
  • C++14/17/20:这一规则保持有效,且嵌套更深的模板(如 vector<map<string, vector<int>>>)也能正确解析。

完整对比示例

#include<iostream>
#include<vector>
#include<list>
#include<map>

// 一个简单的模板类,用于演示
template<typename T>
structWrapper {
    T value;
};

intmain(){
// ---------- C++98/03 风格 ----------
std::vector<std::list<int> > old_style;      // 需要空格
    Wrapper<std::vector<int> > old_wrapper;      // 需要空格

// ---------- C++11 及之后风格 ----------
std::vector<std::list<int>> new_style;       // 直接使用 >>
    Wrapper<std::vector<int>> new_wrapper;       // 更清晰
std::map<std::stringstd::vector<int>> map_of_vectors; // 常见用法

// 嵌套三层也正确
std::vector<std::map<std::stringstd::vector<int>>> complex;

std::cout << "C++11 之后,嵌套模板的 >> 写法完全合法!\n";
return0;
}

编译验证

  • 使用 -std=c++98 或 -std=c++03 编译含有 >>(无空格)的代码会报错。
  • 使用 -std=c++11 或更高标准编译,上述代码全部通过。

因此,如果你的项目允许使用 C++11 或更新标准,建议直接采用简洁的 >> 写法;如果仍需兼容古老编译器,请保留空格。