首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法在包含两个或多个范围的锁步范围内调用每个

无法在包含两个或多个范围的锁步范围内调用每个
EN

Stack Overflow用户
提问于 2015-11-18 12:16:00
回答 3查看 102关注 0票数 2

http://dpaste.dzfl.pl/76c79f1f12ab

代码语言:javascript
复制
void main(){
  import std.container;
  import std.stdio;
  import std.algorithm.iteration;
  import std.range;
  Array!int ai = [1,2,3,4];
  Array!int ai1 = [1,2,3,4];
  Array!int ai2 = [1,2,3,4];

  auto arange = lockstep(ai[],ai1[]);
  arange.each!((a,b) => writeln(a, b));

  auto arange2 = lockstep(ai[],ai1[],ai2[]);
  arange2.each!((a,b,c) => writeln(a, b, c));
}

错误:模板std.algorithm.iteration.each无法从参数类型推断函数!((a,b,c) =>写(a,b,c))(锁步!(RangeT!(数组!int),RangeT!(数组!int),RangeT!(数组!int)),候选人是: Std.algorithm.iteration.each(别名pred = "a")

arange工作,但arange2不工作,因为编译器无法推断函数。如果显式添加参数类型,甚至会出现错误。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-18 13:37:41

我认为这个问题是因为each的每个重载都有以下模板约束

代码语言:javascript
复制
void each(Range)(Range r)
    if (isRangeIterable!Range && !isForeachIterable!Range);

void each(Iterable)(Iterable r)
    if (isForeachIterable!Iterable)

isRangeIterable定义为:

代码语言:javascript
复制
enum isRangeIterable(R) =
    isInputRange!R &&
    (isRangeUnaryIterable!R || isRangeBinaryIterable!R);

isForeachIterable也是如此。

因此,lockstep(Range, Range, Range)不能使用each,因为它只需要一个一元函数或一个二进制函数(这两个函数都只需要一个范围)。这不能用lockstep作为“范围”(请注意括号),它返回的只是定义了一个each不支持的三进制opApply。这就是为什么lockstep(Range, Range)工作而不是lockstep(Range, Range, Range)的原因(顺便说一句,这只是巧合,因为第一个参数是指由Array!int提供的索引。您的代码没有执行您认为的那样)。

这似乎是lockstepeach设计中的一个bug;稍后我将为此提交一个bug报告。至于解决办法,目前使用的是常规的foreach循环而不是each

票数 3
EN

Stack Overflow用户

发布于 2015-11-18 14:18:19

lockstep实际上并不返回一个范围;它返回一个带有opApply方法的结构,foreach使用该方法。这是因为范围的front方法只能返回一个值,但是lockstep必须向foreach循环提供n值。each显然对opApply结构有一定的支持(尽管双范围锁步“range”工作的事实有点错误;第一个参数是当前索引)。

相反,您可以使用std.range.zip函数。这与lockstep完全一样,但将结果封装在一个元组中,让front返回所有结果。但是,它要求您解压元组。

示例:

代码语言:javascript
复制
auto arange2 = zip(ai[],ai1[],ai2[]);
arange2.each!(elems => writeln(elems.expand));
票数 3
EN

Stack Overflow用户

发布于 2015-11-18 18:51:05

其他的答案很好地解释了为什么这不适用于each在phobos中的当前实现。

只是为了好玩,如果您真的想要一个可以与任意数量的params一起工作的each

代码语言:javascript
复制
void each(alias fn, R)(R r) {
  import std.traits    : arity;
  import std.string    : join, format;
  import std.algorithm : map;
  import std.range     : iota;

  // "arg0, arg1, ..."
  enum args = iota(arity!fn)
    .map!(i => "arg%d".format(i))
    .join(",");

  // "ref arg0, ref arg1, ..."
  enum params = iota(arity!fn)
    .map!(i => "ref arg%d".format(i))
    .join(",");

  // foreach(ref arg0, ref arg1, ... ; r) fn(arg0, arg1, ...); 
  mixin(q{
    foreach(%s; r) fn(%s);
  }.format(params, args));
}

unittest {
  import std.range;
  auto a = [1,2];
  auto b = [3,4];
  auto c = [5,6];
  auto d = [7,8];

  lockstep(a,b).each!((ref int a, int b) => ++a);
  assert(a == [2,3]);

  lockstep(a,b,c).each!((ref int a, int b, int c) => ++a);
  assert(a == [3,4]);

  lockstep(a,b,c,d).each!((ref int a, int b, int c, int d) => ++a);
  assert(a == [4,5]);
}

不幸的是,您必须显式地指定lambda的args的类型。如果没有,则它是一个模板,而不是委托,而且arity无法检索参数计数。

或者您可以只使用foreach,但是嘿,那么您就没有理由用混合和模板来做疯狂的事情了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33779822

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档