【问题标题】:Why this template parameters con­straint doesn't work?为什么这个模板参数约束不起作用?
【发布时间】:2012-04-13 17:50:40
【问题描述】:

阅读templates-revisited

struct S(T : T*) {
  T t;  // t is supposed to be of type 'int*', but it's of type 'int', why?
}

void main() {

  int x = 123;
  S!(int*) s;
  static assert(is(typeof(s.t) == typeof(&x)));
}

以上代码无法编译。

奇怪的是,以下代码确实可以编译:

struct S(T : int*) {
  T t;
}

void main() {

  int x = 123;
  S!(int*) s;
  static assert(is(typeof(s.t) == typeof(&x)));
}

我不明白这种行为。将不胜感激。

【问题讨论】:

  • 如果你尝试struct S(T:void*)
  • 我会指出这些断言不起作用(当然,它们在 2.059 上不起作用),因为您无法比较类型。您需要它们位于 is 表达式中。
  • @JonathanMDavis 不管怎样,在第一个示例中执行s.t = &x 不起作用,我得到Error: cannot implicitly convert expression (& x) of type int* to int。所以我猜这是一个 DMD 错误?
  • @Arlen 我不是在争论这个问题本身。你的意思很清楚,如果你使用正确的is 表达式,问题确实存在。我只是指出这些断言是不正确的。
  • @JonathanMDavis 谢谢,我修好了。

标签: templates d


【解决方案1】:

当一个类型特化(冒号后面的类型)依赖于参数标识符时,例如T : T*,得到的标识符指的是标识符(T)在类型特化(推断类型)如果有匹配。

否则,如果特化是独立的,例如T : int*,则生成的标识符是类型特化的别名。

例子:

=========================================================
Argument T        | Specialization     | Result
=========================================================
void              | T : void           | void
char              | T : void           | <no match>
int*              | T : T*             | int
immutable(char)[] | T : T[]            | immutable(char)
immutable(char)[] | T : immutable(T)[] | char
=========================================================

当传递给模板形参的参数不匹配时,模板将从重载集中删除。如果在找到匹配项之前重载集为空,则会引发错误。

IsExpressionis(...) 主表达式)中存在不匹配时,结果为 false,并且没有符号被引入范围。

【讨论】:

    【解决方案2】:

    正如http://dlang.org/template.html 的参数推导部分所述,在推导模板参数的类型时:

    1. 如果参数没有类型特化,则参数的类型设置为模板参数。
    2. 如果类型特化依赖于类型参数,则该参数的类型设置为 类型参数的对应部分。
    3. 如果在检查了所有类型参数之后,还有任何类型参数没有分配类型,则它们被分配类型 对应于模板参数中相同位置的 TemplateArgumentList。
    4. 如果应用上述规则并没有为每个模板参数生成一个类型,那么这是一个错误。

    与您的情况相对应的示例是:

    template TBar(T : T*) { }
    alias TBar!(char*) Foo3;   // (2) T is deduced to be char
    

    因此,您在第一个示例中看到的是预期行为。因为T 在两边,所以T 最终会被评估为导致模板参数为T* 的结果。所以,由于模板参数是int*T* 将是int*,而T 最终是int。你所拥有的与std.traits.pointerTarget 非常相似:

    /**
    Returns the target type of a pointer.
    */
    template pointerTarget(T : T*)
    {
        alias T pointerTarget;
    }
    

    您的第二个示例编译,因为该模板要求 T 可以隐式转换为 int*。由于int* 可以隐式转换为自身,因此当您将int* 作为模板参数传递时,它就可以工作。给您带来麻烦的是T 在两边,因为表达式的右侧依赖于左侧。

    现在,我假设您实际上打算在这里测试的是模板参数是一个指针?如果是这种情况,那么您应该使用std.traits.isPointer

    struct S(T)
        if(isPointer!T)
    {
        T t;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 2010-11-19
      相关资源
      最近更新 更多