http://dpaste.dzfl.pl/76c79f1f12ab
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不工作,因为编译器无法推断函数。如果显式添加参数类型,甚至会出现错误。
发布于 2015-11-18 13:37:41
我认为这个问题是因为each的每个重载都有以下模板约束
void each(Range)(Range r)
if (isRangeIterable!Range && !isForeachIterable!Range);
void each(Iterable)(Iterable r)
if (isForeachIterable!Iterable)将isRangeIterable定义为:
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提供的索引。您的代码没有执行您认为的那样)。
这似乎是lockstep和each设计中的一个bug;稍后我将为此提交一个bug报告。至于解决办法,目前使用的是常规的foreach循环而不是each。
发布于 2015-11-18 14:18:19
lockstep实际上并不返回一个范围;它返回一个带有opApply方法的结构,foreach使用该方法。这是因为范围的front方法只能返回一个值,但是lockstep必须向foreach循环提供n值。each显然对opApply结构有一定的支持(尽管双范围锁步“range”工作的事实有点错误;第一个参数是当前索引)。
相反,您可以使用std.range.zip函数。这与lockstep完全一样,但将结果封装在一个元组中,让front返回所有结果。但是,它要求您解压元组。
示例:
auto arange2 = zip(ai[],ai1[],ai2[]);
arange2.each!(elems => writeln(elems.expand));发布于 2015-11-18 18:51:05
其他的答案很好地解释了为什么这不适用于each在phobos中的当前实现。
只是为了好玩,如果您真的想要一个可以与任意数量的params一起工作的each:
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,但是嘿,那么您就没有理由用混合和模板来做疯狂的事情了。
https://stackoverflow.com/questions/33779822
复制相似问题