Thread overview
Erroneous "auto can only be used for template function parameters"?
Jun 20, 2015
Yuxuan Shui
Jun 20, 2015
Yuxuan Shui
Jun 21, 2015
Adam D. Ruppe
Jun 21, 2015
Yuxuan Shui
Jun 22, 2015
Yuxuan Shui
Jun 21, 2015
Yuxuan Shui
Jun 22, 2015
Jesse Phillips
Jun 22, 2015
Yuxuan Shui
June 20, 2015
Try to compile this code snippet:

import std.traits;
template a(R) {
	auto a(S)(auto ref R i) {
		return cast(S)i*2;
	}
}
template ReturnTypeEx(alias A, B) {
	alias ReturnTypeEx = ReturnType!(A!B);
}
template b(alias R) {
	int b(S)(S i) {
		alias Ra = ReturnTypeEx!(R, S);
		return cast(int)R!S(i);
	}
}
void main() {
	alias bb = b!(a!ulong);
	pragma(msg, ReturnTypeEx!(bb, int));
}

DMD reports:
sadf.d(3): Error: auto can only be used for template function parameters
sadf.d(8): Error: template instance sadf.a!ulong.A!int error instantiating
sadf.d(12):        instantiated from here: ReturnTypeEx!(a, int)
sadf.d(8):        instantiated from here: A!int
sadf.d(18):        instantiated from here: ReturnTypeEx!(b, int)
sadf.d(18):        while evaluating pragma(msg, ReturnTypeEx!(b, int))

But a(S)(auto ref R) is indeed a template function, so I don't understand.
June 20, 2015
On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
> Try to compile this code snippet:
>
> import std.traits;
> template a(R) {
> 	auto a(S)(auto ref R i) {
> 		return cast(S)i*2;
> 	}
> }
> template ReturnTypeEx(alias A, B) {
> 	alias ReturnTypeEx = ReturnType!(A!B);
> }
> template b(alias R) {
> 	int b(S)(S i) {
> 		alias Ra = ReturnTypeEx!(R, S);
> 		return cast(int)R!S(i);
> 	}
> }
> void main() {
> 	alias bb = b!(a!ulong);
> 	pragma(msg, ReturnTypeEx!(bb, int));
> }
>
> DMD reports:
> sadf.d(3): Error: auto can only be used for template function parameters
> sadf.d(8): Error: template instance sadf.a!ulong.A!int error instantiating
> sadf.d(12):        instantiated from here: ReturnTypeEx!(a, int)
> sadf.d(8):        instantiated from here: A!int
> sadf.d(18):        instantiated from here: ReturnTypeEx!(b, int)
> sadf.d(18):        while evaluating pragma(msg, ReturnTypeEx!(b, int))
>
> But a(S)(auto ref R) is indeed a template function, so I don't understand.

Another thing I discovered is instantiation like this: (a!T)!S will result in "C style cast illegal", which is clearly wrong because this is not a cast, (a!T) is not necessarily a type.
June 21, 2015
On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
> auto ref R) is indeed a template function, so I don't understand.

But R is not a parameter on the function itself. It comes from the outside template.

Move it to the inside template, rewrite it as:

	auto a(S, R)(auto ref R i) {
		return cast(S)i*2;
	}

and you should get further.
June 21, 2015
On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>> auto ref R) is indeed a template function, so I don't understand.
>
> But R is not a parameter on the function itself. It comes from the outside template.
>
> Move it to the inside template, rewrite it as:
>
> 	auto a(S, R)(auto ref R i) {
> 		return cast(S)i*2;
> 	}
>
> and you should get further.

But surely nested template should be able to access outer template's parameter.
June 21, 2015
On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>> auto ref R) is indeed a template function, so I don't understand.
>
> But R is not a parameter on the function itself. It comes from the outside template.
>
> Move it to the inside template, rewrite it as:
>
> 	auto a(S, R)(auto ref R i) {
> 		return cast(S)i*2;
> 	}
>
> and you should get further.

Also the same error persists even if I change 'a' to

auto a(S)(auto ref S i)
June 22, 2015
On 6/20/15 10:26 PM, Yuxuan Shui wrote:
> On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
>> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>>> auto ref R) is indeed a template function, so I don't understand.
>>
>> But R is not a parameter on the function itself. It comes from the
>> outside template.
>>
>> Move it to the inside template, rewrite it as:
>>
>>     auto a(S, R)(auto ref R i) {
>>         return cast(S)i*2;
>>     }
>>
>> and you should get further.
>
> But surely nested template should be able to access outer template's
> parameter.

If you have to instantiate it to see how to instantiate it, it doesn't work. General rule of thumb on templates. IFTI only works at one level.

-Steve
June 22, 2015
On Monday, 22 June 2015 at 13:49:21 UTC, Steven Schveighoffer wrote:
> On 6/20/15 10:26 PM, Yuxuan Shui wrote:
>> On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
>>> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>>>> auto ref R) is indeed a template function, so I don't understand.
>>>
>>> But R is not a parameter on the function itself. It comes from the
>>> outside template.
>>>
>>> Move it to the inside template, rewrite it as:
>>>
>>>     auto a(S, R)(auto ref R i) {
>>>         return cast(S)i*2;
>>>     }
>>>
>>> and you should get further.
>>
>> But surely nested template should be able to access outer template's
>> parameter.
>
> If you have to instantiate it to see how to instantiate it, it doesn't work. General rule of thumb on templates. IFTI only works at one level.
>
> -Steve

I can't see any IFTI in my code, can you point it out?
June 22, 2015
On 6/22/15 1:37 PM, Yuxuan Shui wrote:
> On Monday, 22 June 2015 at 13:49:21 UTC, Steven Schveighoffer wrote:
>> On 6/20/15 10:26 PM, Yuxuan Shui wrote:
>>> On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
>>>> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>>>>> auto ref R) is indeed a template function, so I don't understand.
>>>>
>>>> But R is not a parameter on the function itself. It comes from the
>>>> outside template.
>>>>
>>>> Move it to the inside template, rewrite it as:
>>>>
>>>>     auto a(S, R)(auto ref R i) {
>>>>         return cast(S)i*2;
>>>>     }
>>>>
>>>> and you should get further.
>>>
>>> But surely nested template should be able to access outer template's
>>> parameter.
>>
>> If you have to instantiate it to see how to instantiate it, it doesn't
>> work. General rule of thumb on templates. IFTI only works at one level.
>>
> I can't see any IFTI in my code, can you point it out?

Sorry, I misunderstood what is happening here. I don't know what the rules are for auto ref for nested template functions, or for explicit instantiation.

-Steve
June 22, 2015
On Sunday, 21 June 2015 at 02:37:59 UTC, Yuxuan Shui wrote:
> On Sunday, 21 June 2015 at 01:26:51 UTC, Adam D. Ruppe wrote:
>> On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
>>> auto ref R) is indeed a template function, so I don't understand.
>>
>> But R is not a parameter on the function itself. It comes from the outside template.
>>
>> Move it to the inside template, rewrite it as:
>>
>> 	auto a(S, R)(auto ref R i) {
>> 		return cast(S)i*2;
>> 	}
>>
>> and you should get further.
>
> Also the same error persists even if I change 'a' to
>
> auto a(S)(auto ref S i)

I'm not reproducing in DMD 2.067:

    void main() {
        int m;
        a!int(m);
    }
    template a(R) {
        auto a(S)(auto ref S i) {
        }
    }

Note that since template 'a' and function template 'a' have the same name you're invoking IFTI, otherwise the code would look like:

    void main() {
    	int m;
    	z!int.a(m);
    }
    template z(R) {
        auto a(S)(auto ref S i) {
        }
    }

June 22, 2015
On Saturday, 20 June 2015 at 01:50:11 UTC, Yuxuan Shui wrote:
> Try to compile this code snippet:
>
> import std.traits;
> template a(R) {
> 	auto a(S)(auto ref R i) {
> 		return cast(S)i*2;
> 	}
> }
> template ReturnTypeEx(alias A, B) {
> 	alias ReturnTypeEx = ReturnType!(A!B);
> }
> template b(alias R) {
> 	int b(S)(S i) {
> 		alias Ra = ReturnTypeEx!(R, S);
> 		return cast(int)R!S(i);
> 	}
> }
> void main() {
> 	alias bb = b!(a!ulong);
> 	pragma(msg, ReturnTypeEx!(bb, int));
> }
>
> DMD reports:
> sadf.d(3): Error: auto can only be used for template function parameters
> sadf.d(8): Error: template instance sadf.a!ulong.A!int error instantiating
> sadf.d(12):        instantiated from here: ReturnTypeEx!(a, int)
> sadf.d(8):        instantiated from here: A!int
> sadf.d(18):        instantiated from here: ReturnTypeEx!(b, int)
> sadf.d(18):        while evaluating pragma(msg, ReturnTypeEx!(b, int))
>
> But a(S)(auto ref R) is indeed a template function, so I don't understand.

After more experimenting, here's what I got. This time no nested templates are involved, this seems more likely an 'auto ref' bug.

import std.traits, std.range;

void a(S)(auto ref S i) { }
void b(S)(auto ref S i) if (isInputRange!S) { }
void c(S)(ref S i) if (isInputRange!S) { }

void devil(alias S)() { }

void main() {
    a!string(""); //Works  <--- This line affects the result of devil!(a!string)
    b!string(""); //Works

    //Next line is weird, it:
    //1. Err, 'auto ref can only be used with template function', if 'a' is not
    //   instantiated with 'a!string' first
    //2. Works, if 'a!string' is done first
    alias x = devil!(a!string);

    alias xx = devil!(b!string); //Err, template doesn't match

    alias xxx = devil!(c!string); //Works
}

I'm using DMD 2.067.1