www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Question about generation of template functions

reply Machine Code <jckj33 gmail.com> writes:
I was writing a recursive function that uses template, I thought 
it would generate the proper template function on the fly to 
match the type in the parameter but it seems to not so so and try 
to use the called function, resulting in the error:

 Error: function foo.serialize!(B).serialize(ref B output) is 
 not callable using argument types (A)
        cannot pass argument output of type A to parameter ref B 
 output
 Error: template instance `foo.serialize!(A)` error instantiating
Code: void main() { A a = A(); serialize(a); } struct Attr { string value; alias value this; } struct A { (Attr("foo")) int n = 10; (Attr("baa")) int k = 30; B b = new B(); } class B { (Attr("hello")) int pl = 10; } void serialize(T)(ref T output) { import std.traits : hasUDA, getUDAs, isAggregateType; import std.meta : Alias; foreach(fieldName; __traits(derivedMembers, T)) { alias field = Alias!(__traits(getMember, T, fieldName)); static if(isAggregateType!(typeof(field))) { serialize!(typeof(field))(output); } static if(hasUDA!(field, Attr)) { enum className = getUDAs!(field, Attr)[0]; writefln("className = [%s]", className); } } }
Aug 28 2019
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, August 28, 2019 2:56:25 PM MDT Machine Code via Digitalmars-d-
learn wrote:
 I was writing a recursive function that uses template, I thought
 it would generate the proper template function on the fly to
 match the type in the parameter but it seems to not so so and try

 to use the called function, resulting in the error:
 Error: function foo.serialize!(B).serialize(ref B output) is
 not callable using argument types (A)

        cannot pass argument output of type A to parameter ref B

 output
 Error: template instance `foo.serialize!(A)` error instantiating
Code: void main() { A a = A(); serialize(a); } struct Attr { string value; alias value this; } struct A { (Attr("foo")) int n = 10; (Attr("baa")) int k = 30; B b = new B(); } class B { (Attr("hello")) int pl = 10; } void serialize(T)(ref T output) { import std.traits : hasUDA, getUDAs, isAggregateType; import std.meta : Alias; foreach(fieldName; __traits(derivedMembers, T)) { alias field = Alias!(__traits(getMember, T, fieldName)); static if(isAggregateType!(typeof(field))) { serialize!(typeof(field))(output); } static if(hasUDA!(field, Attr)) { enum className = getUDAs!(field, Attr)[0]; writefln("className = [%s]", className); } } }
If a parameter is ref, then the type of the argument must be exactly the same type as the parameter. When you call serialize in main, it infers T to be A, becaues you passed it an A. Within serialize, you call serialize and explicitly instantiate it. So, T is then whatever the type is that you provided (which in this case would be typeof(field), whatever that is for each iteration of the compile-time foreach). If typeof(field) is ever not an A, then you can't pass the variable output to it, because output is an A. You need to pass it an lvalue that has the type typeof(field). I'm guessing that you meant to pass the member variables of output to serialize one by one and not output over and over again. - Jonathan M Davis
Aug 28 2019
prev sibling parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Wednesday, 28 August 2019 at 20:56:25 UTC, Machine Code wrote:
 I was writing a recursive function that uses template, I 
 thought it would generate the proper template function on the 
 fly to match the type in the parameter but it seems to not so 
 so and try to use the called function, resulting in the error:

 Error: function foo.serialize!(B).serialize(ref B output) is 
 not callable using argument types (A)
        cannot pass argument output of type A to parameter ref 
 B output
 Error: template instance `foo.serialize!(A)` error 
 instantiating
Code:
 void serialize(T)(ref T output)
 {
 	import std.traits : hasUDA, getUDAs, isAggregateType;
 	import std.meta : Alias;
 	
 	foreach(fieldName; __traits(derivedMembers, T))
 	{
 		alias field = Alias!(__traits(getMember, T, fieldName));
 		static if(isAggregateType!(typeof(field)))
 		{
 			serialize!(typeof(field))(output);
 		}
 		static if(hasUDA!(field, Attr))
 		{
 			enum className = getUDAs!(field, Attr)[0];
 			writefln("className = [%s]", className);
 		}
 	}
 }
You're asking it to be the field type but passing it output. serialize!(typeof(field))(output);
Aug 29 2019
parent Machine Code <jckj33 gmail.com> writes:
That's right, thank you all guys. Found my mistake; should be:

 serialize!(typeof(field))(__traits(getMember, output, 
 fieldName));
Aug 29 2019