Implicit type conversion of an argument when a function is called

John Colvin john.loughran.colvin at gmail.com
Tue Feb 11 08:10:51 PST 2014


On Tuesday, 11 February 2014 at 14:47:31 UTC, Carl Sturtivant 
wrote:
>> With a class you can do this:
>> class Data
>> {
>> 	string s;
>> 	this(string s)
>> 	{
>> 		this.s = s;
>> 	}
>> }
>>
>> void f(Data x ...)
>> {
>> 	import std.stdio;
>> 	writeln(x.s);
>> }
>>
>> void main()
>> {
>>    f("hello"); //convert argument implicitly to type `data`.
>> }
>>
>> See Typesafe Variadic Functions at 
>> http://dlang.org/function.html
>>
>> I don't know why you can't do it with a struct.
>>
>> As a workaround, you can do this:
>>
>> class Construct(T)
>> {
>> 	T t;
>> 	this(Q)(Q q)
>> 	{
>> 		static if(is(Q : T))
>> 		{
>> 			t = q;
>> 		}
>> 		else
>> 		{
>> 			this.t = T(q);
>> 		}
>> 	}
>> }
>>
>> struct Data
>> {
>> 	string s;
>> }
>>
>> void f(Construct!Data xC ...) //construct the wrapper class
>> {
>> 	auto x = xC.t; //get the contents.
>> 	
>> 	import std.stdio;
>> 	writeln(x.s);
>> }
>>
>> void main()
>> {
>> 	f("hello");
>> 	f(Data("world"));
>> }
>>
>>
>> Overall it's probably best to define f as:
>>
>> void f(Data x)
>> {
>> 	import std.stdio;
>> 	writeln(x.s);
>> }
>>
>> void f(Construct!Data xC ...)
>> {
>> 	.f(xC.t);
>> }
>>
>> To avoid any overhead when calling normally as well as 
>> separating the definition of the real function from the 
>> concern of automatic construction/conversion.
>
> Nice technique, I'll remember that. Presumably this can't be 
> extended to functions with more than one Data parameter.

You are correct, although you can of course just create a normal 
D-style variadic function overload that does any conversions 
necessary and then forwards to the original function, but you get 
less of a helping hand from the language. In general it's harder 
as you could have multiple constructors that take different 
numbers of arguments. My example above should work for any number 
of args, but if you restrict yourself to 1 to 1 conversions:

void g(A a, B b) {}

void g(TL ...)(TL args)
     if(TL.length == 2)
{
     //do conversions if possible and pass the converted args to
     //g(A,B).
}


In all of this I haven't taken any care over ref-ness. In order 
to get that correct you likely need to use auto ref and maybe 
std.algorithm.forward, I haven't thought much about it.


More information about the Digitalmars-d-learn mailing list