无法在包含 2 个或更多范围的锁步范围内调用每个
Unable to call each on a lockstep range containing 2 or more ranges
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));
}
Error: template std.algorithm.iteration.each cannot deduce function
from argument types !((a, b, c) => writeln(a, b,
c))(Lockstep!(RangeT!(Array!int), RangeT!(Array!int),
RangeT!(Array!int))), candidates are:
/opt/compilers/dmd2/include/std/algorithm/iteration.d(820):
std.algorithm.iteration.each(alias pred = "a")
arange
有效,但 arange2
无效,因为编译器无法推导该函数。如果我显式添加参数类型,甚至会出现错误。
我认为这个问题是因为 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
一起使用,因为 "range"(注意括号)它 returns 只定义一个三元组 opApply
,each
不支持。这就是 lockstep(Range, Range)
有效但 lockstep(Range, Range, Range)
无效的原因(顺便说一句,这只是巧合,因为第一个参数是一个索引,由 Array!int
提供。您的代码确实不要做你认为它做的事)。
这似乎是 lockstep
和 each
设计中的错误;我稍后会为它提交错误报告。至于解决方法,暂时使用常规 foreach
循环而不是 each
.
lockstep
实际上 return 不是一个范围;它 return 是一个具有 opApply
方法的结构,foreach
使用该方法。这是因为范围的 front
方法只能 return 一个值,但是 lockstep
必须向 foreach 循环提供 n
值。 each
显然对 opApply
结构有一些支持(尽管双范围锁步 'range' 工作的事实有点错误;第一个参数旨在成为当前索引) .
相反,您可以使用 std.range.zip
函数。这与 lockstep
完全一样,但将结果包装在一个元组中,让 front
return 所有结果。不过,它要求您解压元组。
示例:
auto arange2 = zip(ai[],ai1[],ai2[]);
arange2.each!(elems => writeln(elems.expand));
其他答案很好地解释了为什么这不适用于 phobos 中 each
的当前实现。
只是为了好玩,如果你真的想要一个可以使用任意数量参数的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 参数的类型。如果你不这样做,它是一个模板而不是委托,arity
无法检索参数计数。
或者您可以只使用 foreach
,但是,嘿,这样您就没有借口用混入和模板做一些疯狂的事情了。
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));
}
Error: template std.algorithm.iteration.each cannot deduce function from argument types !((a, b, c) => writeln(a, b, c))(Lockstep!(RangeT!(Array!int), RangeT!(Array!int), RangeT!(Array!int))), candidates are: /opt/compilers/dmd2/include/std/algorithm/iteration.d(820):
std.algorithm.iteration.each(alias pred = "a")
arange
有效,但 arange2
无效,因为编译器无法推导该函数。如果我显式添加参数类型,甚至会出现错误。
我认为这个问题是因为 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
一起使用,因为 "range"(注意括号)它 returns 只定义一个三元组 opApply
,each
不支持。这就是 lockstep(Range, Range)
有效但 lockstep(Range, Range, Range)
无效的原因(顺便说一句,这只是巧合,因为第一个参数是一个索引,由 Array!int
提供。您的代码确实不要做你认为它做的事)。
这似乎是 lockstep
和 each
设计中的错误;我稍后会为它提交错误报告。至于解决方法,暂时使用常规 foreach
循环而不是 each
.
lockstep
实际上 return 不是一个范围;它 return 是一个具有 opApply
方法的结构,foreach
使用该方法。这是因为范围的 front
方法只能 return 一个值,但是 lockstep
必须向 foreach 循环提供 n
值。 each
显然对 opApply
结构有一些支持(尽管双范围锁步 'range' 工作的事实有点错误;第一个参数旨在成为当前索引) .
相反,您可以使用 std.range.zip
函数。这与 lockstep
完全一样,但将结果包装在一个元组中,让 front
return 所有结果。不过,它要求您解压元组。
示例:
auto arange2 = zip(ai[],ai1[],ai2[]);
arange2.each!(elems => writeln(elems.expand));
其他答案很好地解释了为什么这不适用于 phobos 中 each
的当前实现。
只是为了好玩,如果你真的想要一个可以使用任意数量参数的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 参数的类型。如果你不这样做,它是一个模板而不是委托,arity
无法检索参数计数。
或者您可以只使用 foreach
,但是,嘿,这样您就没有借口用混入和模板做一些疯狂的事情了。