Generics 字符串(数组)上回文算法的模板冲突

Generics 字符串(数组)上回文算法的模板冲突,generics,d,palindrome,range,dmd,Generics,D,Palindrome,Range,Dmd,在看过优秀的文章之后,我测试了下面给出的回文算法 import std.exception; bool isPalindrome(T)(T[] a) { for (; a.length > 1; a = a[1 .. $-1]) { if (a[0] != a[$-1]) { return false; } } return true; } bool isPalindrome(Range)(Range r) { for (; !r.empty

在看过优秀的文章之后,我测试了下面给出的回文算法

import std.exception;

bool isPalindrome(T)(T[] a)
{
  for (; a.length > 1; a = a[1 .. $-1]) {
    if (a[0] != a[$-1]) {
      return false;
    }
  }
  return true;
}

bool isPalindrome(Range)(Range r)
{
  for (; !r.empty; r.popFront(), r.popBack()) {
    if (a.front != a.back) {
      return false;
    }
  }
  return true;
}

unittest {
  enforce(isPalindrome("dallassallad"));
}
数组版本在字符串上运行良好,但当我将范围版本添加到同一编译单元时,DMD(2.062)会抱怨:

palindrome.d(31): Error: template palindrome.isPalindrome matches
more than one template declaration,
palindrome.d(10):isPalindrome(T)(T[] a) and
palindrome.d(20):isPalindrome(Range)(Range r)
我的猜测是将范围的使用限制为不包括数组大小写。我该怎么做

我还测试了删除阵列版本,但随后出现了错误

/home/per/Work/cognia/palindrome.d(22): Error: no property 'empty' for type 'string'
/home/per/Work/cognia/palindrome.d(22): Error: undefined identifier 'popFront'
/home/per/Work/cognia/palindrome.d(22): Error: undefined identifier 'popBack'
/home/per/Work/cognia/palindrome.d(23): Error: undefined identifier a, did you mean variable r?
/home/per/Work/cognia/palindrome.d(23): Error: undefined identifier a, did you mean variable r?
/home/per/Work/cognia/palindrome.d(27): Warning: statement is not reachable
/home/per/Work/cognia/palindrome.d(31): Error: template instance palindrome.isPalindrome!(string) error instantiating
我觉得range版本不适合我觉得奇怪的数组


如何操作?

向第二个模板添加模板约束,如下所示:

bool isPalindrome(Range)(Range r)
    if (!isArray!Range)
您需要为
isArray
模板导入
std.traits

如果只想使用第二个模板,则必须导入
std.array
,该模板使用
UFCS
(统一函数调用语法)使数组具有
front
popFront
empty
等功能

UFCS基本上意味着:

int[] x;
int f = x.front;
翻译成:

int f = front(x);
std.array
中的数组定义了
front
和其他数组,这使您可以像使用范围一样使用数组。您可以对自己的类型使用相同的技术。可以在结构/类内部定义范围函数,例如
front
,也可以在外部将其定义为将结构/类作为其第一个参数的函数


有关更多信息,请参阅文档。

还请注意,通用版本中存在一个令人尴尬的错误,因为它可能试图减少空范围。更正版本为:

bool isPalindrome(Range)(Range r)
{
    while (!r.empty) {
        if (a.front != a.back) {
          return false;
        }
        r.popFront();
        if (r.empty) {
            return true;
        }
        r.popBack();
    }
    return true;
}

还有
scope(exit)
scope(failue)
在幻灯片中的向后位置(因此在回滚之前进行了清理),这是性能方面的问题,为了使数组与通用数组保持专用,您可以使用
std.datetime
中的
std.datetime
进行一些计时和比较。在汇编级别,通过所有优化和-inline,这两个函数最终可能是相同的。专门处理数组的函数使用切片,而通用函数使用辅助函数。但是,通用的方法更为正确,因为它可以正确地处理字符串范围(或字符串数组),因为
front
调用可以正确地解码代码点,而专用的数组版本最终会比较代码单位。