I am trying to write a template to define a three procedures which are identical except in the number of generic arguments they take and the number of generic arguments of the types. Is there a way to do this without having to write the same procedure three times?
Specifically it would be nice if the generic parameters could be passed as an argument to the template. For example to generate the code:
proc Test*(self: var Test_Type_Zero) =
echo $self.Name
proc Test*[A](self: var Test_Type_One[A]) =
echo $self.Name
proc Test*[A, B](self: var Test_Type_Two[A, B]) =
echo $self.Name
I would like to be able to write something like the following:
template Test_Template*(vType: untyped, vGen: untyped) =
proc Test*`vGen`(self: var vType`vGen`) =
echo $self.Name
Test_Template(Test_Type_Zero, void)
Test_Template(Test_Type_One, [A])
Test_Template(Test_Type_Two, [A, B])
instead of having to write something like:
template Test_Template_Zero*(vType: untyped) =
proc Test*(self: var vType) =
echo $self.Name
template Test_Template_One*(vType: untyped) =
proc Test*[A](self: var vType[A]) =
echo $self.Name
template Test_Template_Two*(vType: untyped) =
proc Test*[A, B](self: var vType[A, B]) =
echo $self.Name
Test_Template_Zero(Test_Type_Zero)
Test_Template_One(Test_Type_One)
Test_Template_Two(Test_Type_Two)
This unfortunately seems to be right at the edge of what is possible with templates. Mostly because of the special case of having no generic arguments. However a macro is able to deal with it easily enough:
import macros
type
Test_Type_Zero = object
Name: string
Test_Type_One[A] = object
Name: string
Test_Type_Two[A, B] = object
Name: string
macro Test_Template*(vType: untyped, vGen: varargs[untyped]): untyped =
if vGen.len == 0:
quote do:
proc Test*(self: var `vType`) =
echo $self.Name
else:
quote do:
proc Test*[`vGen`](self: var `vType`[`vGen`]) =
echo $self.Name
Test_Template(Test_Type_Zero)
Test_Template(Test_Type_One, A)
Test_Template(Test_Type_Two, A, B)
Note that I switched the syntax for Test_Template
to just list the arguments instead of requiring them to be in a bracket. This just makes the macro a bit easier, but you could certainly make vGen
take an untyped
argument and parse out the elements you need from the bracket element you would get with your initial syntax.