Thread overview
Problem with templated alias as delegate parameter type
Jan 12, 2021
cc
Jan 12, 2021
Ali Çehreli
Jan 12, 2021
cc
January 12, 2021
Given the following program:

struct PingQuery {
	string msg;
}
struct PingResponse {
	string msg;
}
template send(T) {
	void send(T query, void delegate(PingResponse) callback) {
		writefln("Sending: %s", query);
		if (callback) {
			PingResponse resp;
			resp.msg = query.msg;
			callback(resp);
		}
	}
}
void main() {
	send(PingQuery("helo"), (resp) {
		writefln("Got response: %s", resp);
	});
}

This works, but as you can see the PingResponse struct is hardcoded in the send function.  If I try to make it a part of the template in a way such as this:

struct PingQuery {
	alias RESPONSE = PingResponse;
	string msg;
}
struct PingResponse {
	string msg;
}
template send(T) {
	static assert(is(T.RESPONSE == PingQuery.RESPONSE)); // this succeeds at least

	void send(T query, void delegate(T.RESPONSE) callback) {
		writefln("Sending: %s", query);
		if (callback) {
			T.RESPONSE resp;
			resp.msg = query.msg;
			callback(resp);
		}
	}
}
void main() {
	send(PingQuery("helo"), (resp) {
		writefln("Got response: %s", resp);
	});
}
I get:
delegatetest.d(48): Error: template `delegatetest.send` cannot deduce function from argument types `!()(PingQuery, void)`, candidates are:
delegatetest.d(35):        `send(T)(T query, void delegate(T.RESPONSE) callback)`

Same error if I use a nested struct (e.g. struct PingQuery { struct RESPONSE {} }) instead of an alias.  Currently using DMD32 D Compiler v2.095.0-dirty (win64).


January 12, 2021
On 1/12/21 12:58 PM, cc wrote:

>      void send(T query, void delegate(T.RESPONSE) callback) {

That wants a delegate that takes a T.RESPONSE (PingResponse in this case). However, the following lambda is in fact a template:

>      send(PingQuery("helo"), (resp) {

You specify the type there and it works:

    send(PingQuery("helo"), (PingResponse resp) {

Ali

January 12, 2021
On Tuesday, 12 January 2021 at 21:32:14 UTC, Ali Çehreli wrote:
> On 1/12/21 12:58 PM, cc wrote:
>
> >      void send(T query, void delegate(T.RESPONSE) callback) {
>
> That wants a delegate that takes a T.RESPONSE (PingResponse in this case). However, the following lambda is in fact a template:
>
> >      send(PingQuery("helo"), (resp) {
>
> You specify the type there and it works:
>
>     send(PingQuery("helo"), (PingResponse resp) {
>
> Ali

That seems to work, thanks.  I ended up having to define a second template parameter:

template send(T,TR) if (is(TR == T.RESPONSE)) {
	void send(T query, void delegate(TR) callback) {
...