I need get the type of container item(seq, array, iterator etc), so I write an template to get the item type, but when work with the generic, sometime it will fail to compile using the wrapper. Here is the code
import macros
template getTypeOfItem(t: untyped): auto =
type(t[0])
template getType(t: untyped): auto =
type(t[0])
template foo1(t: untyped) =
var x: type(t[0])
template foo2(t: untyped) =
var x: getType(t)
template foo3(t: untyped) =
var x: getTypeOfItem(t)
proc foo[T](x: seq[seq[T]]) =
foo1(x) # this works
foo2(x) # this works too if we import the macros
# without import macros, it fail to compile too
# because there is proc in the macros named getType
# very strange why it affect
foo3(x) # this works for non generic function
# but it fail in this function
foo(@[@[1,2], @[3,4]])
My question is:
Thank you.
The compiler show the following message:
ttype.nim(29, 4) template/generic instantiation from here
ttype.nim(16, 24) Error: type expected
I don't quite understand what you are trying to achieve, something like this or no?
import typetraits
template underlyingType[T](a:seq[T]): typedesc =
when T is seq:
underlyingType(a[0])
else:
T
let a = @[1,2,3]
let b = @[a, a]
echo underlyingType(a).name # prints int
echo underlyingType(b).name # prints int
@cdome Thank you.
I am writing function like map, it will take the type array, slice, seq, iterator, etc as parameter, because the iterator cannot be treated as typed, so I cannot use typed(If the paramter type is typed, the function in the code can compile successfully).
The code like this works:
type outType = type((
block:
when compiles(seq1.len) and not (seq1 is string):
when seq1 is array[1, Slice]: (var it{.inject.}: type(seq1[0].a);)
else: (var it{.inject.}: type(seq1[0]);)
elif seq1 is Slice: (var it{.inject.}: type(seq1.a);)
else: (var it{.inject.}: type(seq1);)
op))
var result: seq[outType] = @[]
I have several function like this, so I hope I can use an template to wrapper the code rather than copy/paste, but if I put the code in another template, I get the compiler error.
@cdome That doesn't work, because iterator is treated as untyped, and untyped parameter cannot be overloaded. The following code cannot compile.
proc f1(t: seq[int]) = discard
template f1(t: untyped) = discard
f1(@[1])
f1(countup(1,3))
@mashingan Yes, I can convert the iterator to seq and all works. But it not the way I want. I hope the iterator is same as seq, like following code:
print collectz(1..5, @[toSeq(1..it)])
print collectz(@[1,2,3], @[toSeq(1..it)])
print collectz(countup(1,4), @[toSeq(1..it)])
print collectz(x <- 1..5, @[toSeq(1..x)])
print collectz(x <- @[1,2,3], @[toSeq(1..x)])
print collectz(x <- countup(1,4), @[toSeq(1..x)])
@LeuGim
One little question. When I import the macros, the getType of this file is used, not the macros's getType, this is strange. That's mean import macros affect the template in this file can be used or not.
I found a way to deal with the problem finally. We cannot define an template which return an 'type' (sometime it will fail to compile), but if I return a variable of the type, it is ok, then I can get the type of the variable.
template get_val_from_item(seq1: untyped): untyped =
var result: type((when compiles(seq1.len): seq1[0] elif seq1 is Slice: seq1.a else: seq1))
result
template foo1(t: untyped) =
var x: type(get_val_from_item(t))
proc foo[T](x: seq[seq[T]]) =
foo1(x)
echo x