为什么C ++不能更容易对类型进行编译时查询?

时间:2014-01-13 21:55:01

标签: c++ templates c++11 generic-programming sfinae

我刚开始学习模板元编程技巧,可以让你查询类型。

例如,SFINAE允许我们通过使用重载和返回类型sizeof比较来检查类型在编译时是否具有特定的typedef或函数。

问:那么,为什么不(如果在C ++ 11/14中有更好的方法,请纠正我)语言提供更好的机制/接口来进行关于类型的这些查询?< / p>

编辑:我想澄清一下这不是一个咆哮(如果听起来那么我很抱歉)。由于我只是开始欣赏模板的强大功能,我想确保我的思维过程不会搞砸。

对于我想要进行这些查询的每个模板类/函数,我必须创建一个SFINAE特定版本。请求编译器“T是否有一个名为A的成员”或“T是否有一个函数<return type> (arg list)”的单个接口不是更清洁的方式吗?当然,编译器具有与用户定义类型相关的所有知识 - 它只需要将它暴露给程序员进行编译时查询。

问:依赖这种通用功能是设计/思考模板的一种不好的方法吗?如果是这种情况,请说明你的理由(如果可能的话,用完成任务的例子)。

2 个答案:

答案 0 :(得分:8)

模板元编程,SFINAE技巧&amp;合。实际上并不是为了做这件事而设计的。 C ++中的模板元编程很容易被发现。

模板启动就像编写类型通用代码一样,添加了更多功能来覆盖极端情况(SFINAE的诞生是为了避免在同一程序中提取不相关模板时可能发生的编译器错误),然后有一天发现某人C ++模板提供了图灵完备的元语言,允许执行有关类型的查询,在编译时执行计算等。

因此,C ++中的模板元编程难以理解,难以编写,难以调试,编译很悲惨,因为它主要是滥用其他用法的东西。模板碰巧是如此强大,但实际上并没有为此设计它们。

C ++ 11为这种用法提供了一些库支持(以及一些核心语言支持),但这并没有改变这种情况的本质。

另外,如果你想要我的意见,模板元编程目前被严重滥用;有了它你可以建立像Boost.Spirit这样的怪物,但你可能不应该。

答案 1 :(得分:2)

SFINAE感觉就像是黑客,因为它是。你想做的就是反思。

现在起初听起来很简单,但基本问题在于一个简单的问题:你怎么知道任意对象是什么类型的?

在具有知道每个对象的VM /运行时的语言中,这通过直接询问运行时/ VM 来解决。在C ++模板碰巧为您提供了一个转义路由,因为在某些点必须实例化模板。在实例化的那一点,编译器必须知道类型。 SFINAE本质上旨在在编译时捕获这些知识并将其重新用于编码指令,这些指令在运行时评估时将产生正确的结果以确定实例化模板的类型。

除了编译器首先没有实现的“普通”C ++模板之外,SFINAE几乎不需要额外的机制。

为了在没有像SFINAE这样的技巧的情况下在编译时进行适当的反射,对于没有外部依赖关系的静态链接程序,仅仅必须解决暂停问题。这是明智的人,编译器作者甚至语言委员会都非常希望避免的。

为了在一般情况下执行此操作,其中包括您编写将在未来作为DSO通过其他代码链接的库代码...您必须花时间去未来只是为了检查未来的代码。所以,是的,这是不可能的。

因此,您需要有关类型和方法的正确运行时信息才能执行您真正想要执行的操作。但是SFINAE允许你使用快捷方式,因为你可以使用在实例化时传递类型的事实来使用模板中的类型变量和编译时sizeof提取信息,以将编译时类型变量导出为常量生成的代码作为模板实例化的副作用。如上所述,它感觉像是黑客的原因是因为它是一个。