Pau*_*nta 29 c++ syntax templates d
在C++模板中使用尖括号进行实例化,vector<int>
Java和C#语言对其泛型使用相同的语法.
然而,D的创造者对尖括号带来的问题非常直言不讳,并且他们提出了一种新的语法foo!(int)
- 但我从未见过关于尖括号带来的问题的太多细节.
其中一个是用另一个模板实例化模板时vector<vector<int>>
,这会导致一些(较旧的?)编译器将尾随的">>"与位移或流操作符混淆.解决方案是在两个尖括号之间插入一个空格,但现在还没有编译器能够解析这种语法吗?
另一个问题是使用大于运算符时foo<3 > 2>
.解析器会认为运算符实际上关闭了模板实例化; 修复是介绍括号foo<(3 > 2)>
.但我不认为有很多情况你需要这样做,无论如何,我宁愿在需要时输入额外的括号,而不是引入新的语法并且总是要输入感叹号.
使用尖括号还有哪些其他问题使D开发人员创建了新语法?
Kon*_*lph 25
但是现在还没有编译器能够解析那种语法吗?
当然.但这远非微不足道.特别是,它会阻止您在不知道上下文的词法分析器和解析器之间实现清晰的分离.对于需要解析C++的语法高亮显示器和其他支持工具来说,这尤其令人厌烦,但是不希望/可以实现完全成熟的语法分析器.
它使C++难以解析,许多工具根本不会打扰.这是生态系统的净损失.换句话说:它使得开发解析工具的成本更高.
例如,ctags
某些模板定义失败,这使得它无法用于我们当前的C++项目.很烦人.
但我不认为有很多情况你需要[区分尖括号和小于]
你需要多久做一次并不重要.您的解析器仍需要处理此问题.
D决定放下角度支持是一个明智的选择.鉴于这是一个净收益,任何一个理由都足够了.
Mat*_* M. 25
就个人而言,我看到的最可怕的问题是在依赖的上下文中调用模板函数:
template <typename T>
void foo(T t) {
t.bar<3>();
}
Run Code Online (Sandbox Code Playgroud)
这看起来很简单,但实际上是不正确的.C++标准要求引入template
关键字以消除歧义t.bar < 3
与方法调用产生:
t.template bar<3>(); // iirk
Run Code Online (Sandbox Code Playgroud)
litb做了一些关于编译器可能提出的解释的非常有趣的帖子.
关于这个>>
问题,它在C++ 0x中修复,但需要更聪明的编译器.
问题是使语言语法无上下文.当词法分析器对程序进行标记时,它使用一种称为maximal munch的技术,这意味着它总是需要可能指定令牌的最长字符串.这意味着它>>
被视为正确的bitshift运算符.所以,如果你有类似的东西vector<pair<int, int>>
,>>
最后被视为正确的bitshift运算符而不是模板实例化的一部分.对于它来治疗>>
在这方面有所不同,它必须是上下文敏感的,而不是上下文自由 -那就是它必须真正关心的令牌被解析的上下文.这使得词法分析器和解析器相当复杂.词法分析器和解析器越复杂,错误的风险就越高 - 更重要的是,工具实现它们的难度越大,这意味着工具越少.当IDE或代码编辑器中的语法突出显示等实现变得复杂时,这就是一个问题.
通过使用!()
- 这将导致vector!(pair!(int, int))
相同的声明 - D避免了上下文敏感性问题.D在其语法中明确地做了许多这样的选择,其思想是使工具在需要时更容易实现lexing或解析,以便他们做他们所做的事情.因为除了使用!()
其他语言中使用模板或泛型的程序员有点陌生之外,使用模板确实没有任何缺点<>
,这是一种合理的语言设计选择.
使用尖括号语法时,您使用或不使用会产生歧义的模板的频率 - 例如vector<pair<int, int>>
- 与语言无关.无论如何,工具必须实现它.决定使用!()
而不是<>
完全是简化工具语言的问题,而不是程序员.虽然你可能会或可能不会特别喜欢这种!()
语法,但它很容易使用,因此它最终不会给程序员带来任何问题,除了学习它以及它可能违背他们个人偏好的事实.
在C++中,另一个问题是预处理器不理解尖括号,因此失败:
#define FOO(X) typename something<X>::type
FOO(std::map<int, int>)
Run Code Online (Sandbox Code Playgroud)
问题是预处理器认为用两个参数调用FOO:std::map<int
和int>
.这是一个更广泛问题的一个例子,它通常是模糊的,无论符号是运算符还是括号.
归档时间: |
|
查看次数: |
6236 次 |
最近记录: |