模板和宏中的类型化vs未类型化vs expr vs stmt [英] typed vs untyped vs expr vs stmt in templates and macros

查看:111
本文介绍了模板和宏中的类型化vs未类型化vs expr vs stmt的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在使用模板和宏,但是我不得不说我几乎没有找到有关这些重要类型的信息.这是我的肤浅理解:

I've been lately using templates and macros, but i have to say i have barely found information about these important types. This is my superficial understanding:

  • typed/expr是以前必须存在的东西,但是您可以使用.immediate.克服它们.
  • 未类型化/stmt是以前未定义的/一个或多个语句.

这是一个非常模糊的类型概念.我想对它们进行更好的解释,包括应将哪些类型用作返回值.

This is a very vague notion of the types. I'd like to have a better explanation of them, including which types should be used as return.

推荐答案

这些不同参数类型的目标是使您在指定编译器应作为宏参数接受哪些内容时提高几种精度.

The goal of these different parameter types is to give you several increasing levels of precision in specifying what the compiler should accept as a parameter to the macro.

让我们想象一个可以解决数学方程的假设宏.它将像这样使用:

Let's imagine a hypothetical macro that can solve mathematical equations. It will be used like this:

solve(x + 10 = 25) # figures out that the correct value for x is 15

在这里,宏仅关心所提供的AST树的结构.不需要同一棵树在当前范围内是有效的表达式(即定义了x,依此类推).宏仅利用Nim解析器的优势,该解析器已经可以解码大多数数学方程式,从而使它们变得更易于处理AST树.这就是untyped参数的作用.他们不会经过语义检查,而您会得到原始的AST.

Here, the macro just cares about the structure of the supplied AST tree. It doesn't require that the same tree is a valid expression in the current scope (i.e. that x is defined and so on). The macro just takes advantage of the Nim parser that already can decode most of the mathematical equations to turn them into easier to handle AST trees. That's what untyped parameters are for. They don't get semantically checked and you get the raw AST.

精度阶梯中的下一个步骤是typed参数.它们使我们能够编写通用的宏,该宏将接受任何表达式,只要它在当前作用域中具有适当的含义(即可以确定其类型)即可.除了更早地捕获错误之外,这还有一个优势,我们现在可以使用宏主体中的表达式类型(使用macros.getType proc).

On the next step in the precision ladder are the typed parameters. They allow us to write a generic kind of macro that will accept any expression, as long as it has a proper meaning in the current scope (i.e. its type can be determined). Besides catching errors earlier, this also has the advantage that we can now work with the type of the expression within the macro body (using the macros.getType proc).

我们可以通过要求特定类型(具体类型或类型类/概念)的表达式来获得更精确的结果.现在,该宏将能够像常规proc一样参与重载解析.重要的是要了解宏仍将接收AST树,因为它会接受可以在编译时评估的表达式和只能在运行时评估的表达式.

We can get even more precise by requiring an expression of a specific type (either a concrete type or a type class/concept). The macro will now be able to participate in overload resolution like a regular proc. It's important to understand that the macro will still receive an AST tree, as it will accept both expressions that can be evaluated at compile-time and expressions that can only be evaluated at run-time.

最后,我们可以要求宏接收在编译时提供的特定类型的值.宏可以使用该值来参数化代码生成.这是静态参数的领域.在宏的主体内,它们不再是AST树,而是普通的类型正确的值.

Finally, we can require that the macro receives a value of specific type that is supplied at compile-time. The macro can work with this value to parametrise the code generation. This is realm of the static parameters. Within the body of the macro, they are no longer AST trees, but rather ordinary well typed values.

到目前为止,我们仅讨论了表达式,但是Nim的宏也接受并生成块,这是我们可以控制的第二个轴. expr通常表示单个表达式,而stmt表示表达式列表(从历史上讲,它的名称来自StatementList,后者在Nim中将表达式和语句统一之前作为一个单独的概念存在).

So far, we've only talked about expressions, but Nim's macros also accept and produce blocks and this is the second axis, which we can control. expr generally means a single expression, while stmt denotes a list of expressions (historically, its name comes from StatementList, which existed as a separate concept before expressions and statements were unified in Nim).

最容易用模板的返回类型说明这种区别.考虑系统模块中的newException模板:

The distinction is most easily illustrated with the return types of templates. Consider the newException template from the system module:

template newException*(exceptn: typedesc, message: string): expr =
  ## creates an exception object of type ``exceptn`` and sets its ``msg`` field
  ## to `message`. Returns the new exception object.
  var
    e: ref exceptn
  new(e)
  e.msg = message
  e

即使认为通过指定expr作为模板的返回类型来构造异常,我们也告诉编译器只有最后一个表达式将被视为模板的返回值.其余语句将内联,但会巧妙地隐藏在调用代码中.

Even thought it takes several steps to construct an exception, by specifying expr as the return type of the template, we tell the compiler that only that last expression will be considered as the return value of the template. The rest of the statements will be inlined, but cleverly hidden from the calling code.

再举一个例子,让我们定义一个特殊的赋值运算符,它可以模拟C/C ++的语义,并允许在if语句中赋值:

As another example, let's define a special assignment operator that can emulate the semantics of C/C++, allowing assignments within if statements:

template `:=` (a: untyped, b: typed): bool =
  var a = b
  a != nil

if f := open("foo"):
  ...

指定具体类型的语义与使用expr的语义相同.如果我们使用默认的stmt返回类型,则编译器将不允许我们传递表达式列表",因为if语句显然希望使用单个表达式.

Specifying a concrete type has the same semantics as using expr. If we had used the default stmt return type instead, the compiler wouldn't have allowed us to pass a "list of expressions", because the if statement obviously expects a single expression.

.immediate.是过去已久的遗产,当时模板和宏不参与重载解析.当我们第一次让他们了解类型系统时,大量的代码需要当前的untyped参数,但是要重构编译器以从一开始就引入它们太困难了,相反,我们添加了.immediate. pragma作为一种方法.对整个宏/模板强制向后兼容.

.immediate. is a legacy from a long-gone past, when templates and macros didn't participate in overload resolution. When we first made them aware of the type system, plenty of code needed the current untyped parameters, but it was too hard to refactor the compiler to introduce them from the start and instead we added the .immediate. pragma as a way to force the backward-compatible behaviour for the whole macro/template.

使用typed/untyped,您可以对宏的各个参数进行更精细的控制,并且.immediate.杂注将逐渐淘汰并弃用.

With typed/untyped, you have a more granular control over the individual parameters of the macro and the .immediate. pragma will be gradually phased out and deprecated.

这篇关于模板和宏中的类型化vs未类型化vs expr vs stmt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆