Umm*_*mma 25 c++ templates d ada generic-programming
C++的一个问题是我们从密集使用模板和模板元编程的代码中获得的可怕错误消息.这些概念旨在解决这个问题,但遗憾的是它们不会出现在下一个标准中.
我想知道,这个问题是否适用于支持通用编程的所有语言?或者C++模板出了什么问题?
不幸的是,我不知道任何其他支持泛型编程的语言(Java和C#泛型太简单了,没有C++模板那么强大).
所以我问你们:D,Ada,Eiffel模板(仿制药)是否也会产生如此丑陋的错误消息?是否可以使用具有强大通用编程范例的语言,但没有丑陋的错误消息?如果是,这些语言如何解决这个问题?
编辑:为downvoters.我真的很喜欢C++和模板.我不是说模板很糟糕.实际上我是泛型编程和模板元编程的忠实粉丝.我只是问为什么我从编译器那里收到如此丑陋的错误信息.
Mat*_* M. 15
问题的核心是,无论上下文如何,错误恢复都很困难.
当你考虑C和C++可怕的语法时,你只能怀疑错误信息并不比这更糟糕!我担心C语法是由那些对语法基本属性一无所知的人设计的,其中一个就是对语境的依赖越少越好,另一个就是你应该努力制作尽可能明确无误.
让我们说明一个常见错误:忘记分号.
struct CType {
int a;
char b;
}
foo
bar() { /**/ }
Run Code Online (Sandbox Code Playgroud)
好的,这是错的,丢失的分号应该去哪里?不幸的是,这是不明确的,它可以在之前或之后去,foo因为:
structint)如果我们有理由,我们可以看到:
foo命名一个类型,那么它属于函数声明fool,恰好是一个类型:/正如您所看到的,错误恢复非常困难,因为我们需要推断出作者的意思,并且语法远非接受.但这并非不可能,大多数错误确实可以或多或少地正确诊断,甚至可以从......中恢复......只需要付出相当大的努力.
似乎工作人员对gcc生成快速代码更感兴趣(我的意思是快速,在gcc 4.6上搜索最新的基准测试)并添加有趣的功能(gcc已经实现了大多数 - 如果不是全部 - C++ 0x)而不是生成易于阅读的错误消息.你能怪他们吗?我不能.
幸运的是,有些人认为准确的错误报告和良好的错误恢复是一个非常有价值的目标,其中一些人已经在CLang工作了很长时间,他们仍在继续这样做.
一些不错的功能,在我的头顶:
std::vector<Name>而不是std::vector<std::basic_string<char, std::allocator<char>>, std::allocator<std::basic_string<char, std::allocator<char>> >使得所有区别)template在从另一个模板方法调用模板方法中丢失的情况下丢失,则正确恢复但是每个人都需要几个小时到几天的工作.
他们当然不是免费的.
现在,概念应该(通常)使我们的生活更轻松.但它们大多未经测试,因此最好将它们从草案中删除.我必须说我为此感到高兴.考虑到C++的相对惯性,最好不要包含尚未彻底修改的功能,概念图并没有让我感到非常激动.他们似乎也没有激动Bjarne或Herb,因为他们说他们将从头开始重新思考下一个标准的概念.
T.E*_*.D. 14
一般来说,我发现用于泛型的Ada编译器错误消息实际上并不比任何其他Ada编译器错误消息更难读.
另一方面,C++模板错误消息因错误小说而臭名昭着.我认为主要的区别在于C++进行模板实例化的方式.问题是,C++模板比Ada泛型更灵活.它非常灵活,几乎就像一个宏预处理器.Boost中的聪明人使用它来实现lambdas甚至整个其他语言之类的东西.
由于这种灵活性,每次首次遇到模板参数的特定排列时,基本上必须重新编译整个模板层次结构.因此,解决了API不兼容问题的问题最终会被提交给糟糕的API客户端进行解密.
在Ada中,泛型实际上是强类型的,并且提供隐藏到客户端的完整信息,就像普通包和子例程一样.因此,如果您收到错误消息,通常只是引用您尝试实例化的通用,而不是用于实现它的整个层次结构.
所以,是的,C++模板错误消息比Ada更差.
现在调试完全是另一回事......
D有两个功能可以提高模板错误消息的质量:约束和static assert.
// Use constraints to only allow a function to operate on random access
// ranges as defined in std.range. If something that doesn't satisfy this
// is passed, the compiler will error before even trying to instantiate
// fun().
void fun(R)(R range) if(isRandomAccessRange!(R)) {
// Do stuff.
}
// Use static assert to check a high level invariant. If
// the predicate is false, the error message will be
// printed and compilation will stop before a screen
// worth of more confusing errors are encountered.
// This function takes any number of ranges to merge sort
// and the same number of temporary buffers to merge into.
void mergeSort(R...)(R ranges) {
static assert(R.length % 2 == 0,
"Must have equal number of ranges to be sorted and temporary buffers.");
static assert(allSatisfy!(isRandomAccessRange, R),
"All arguments to mergeSort must be random access ranges.");
// Implementation
}
Run Code Online (Sandbox Code Playgroud)
Eiffel 拥有所有错误消息中最好的,因为它拥有所有模板系统中最好的。它完全集成到语言中并且运行良好,因为它是唯一在参数中使用协变的语言。
因此,它不仅仅是一个简单的编译器复制和粘贴。不幸的是,用几行来解释差异是不可能的。去看看 EiffelStudio。
| 归档时间: |
|
| 查看次数: |
3714 次 |
| 最近记录: |