www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templated delegate as template argument for structs

reply Simon van Bernem <simon.vanbernem yahoo.de> writes:
I have the following struct declaration:


struct Hash_Table(Key, Value, u32 delegate(ref Key) 
custom_hash_function = null){

...

}


When I try to instance the Type like this:


Hash_Table!(Component*, Component_Tick_Info, (c) => 
hash32(c.handle.bitfield)) my_hash_table;


I get the following compile error


source\vbl.d(2338): Error: undefined identifier `Key`
source\vessel.d(840):        while looking for match for 
`__lambda4!Key`
source\vessel.d(840):        while looking for match for 
`Hash_Table!(Component*, Component_Tick_Info, (c) => 
hash32(c.handle.bitfield))`


vbl.d(2338) is the line of the struct declaration.

I take it from the error that the problem is not actually the 
delegate that I am passing, but the fact that the delegate type 
has another template parameter as the argument type. Can template 
arguments in D not reference previous template arguments? Is 
there some way I can get around this?
Feb 20
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Saturday, 20 February 2021 at 09:16:46 UTC, Simon van Bernem 
wrote:
 I have the following struct declaration:

 struct Hash_Table(Key, Value, u32 delegate(ref Key) 
 custom_hash_function = null)
[snip]
 I take it from the error that the problem is not actually the 
 delegate that I am passing, but the fact that the delegate type 
 has another template parameter as the argument type. Can 
 template arguments in D not reference previous template 
 arguments? Is there some way I can get around this?
The D way would be an alias parameter: struct Hash_Table(Key, Value, alias custom_hash_function) { // ... } Probably also adding a constraint: struct Hash_Table(Key, Value, alias custom_hash_function) if (is_valid_hash_function!(Key, custom_hash_function)) { // ... } // Check if the hash function can be called with a Key // as argument, and the result be assigned to a u32 enum is_valid_hash_function(Key, alias fn) = __traits(compiles, (Key k){ u32 u = fn(k); }); D lets you refer to other template parameters in the same template parameter list in three cases, as far as I know: 1) A type may be a subtype of an earlier parameter: class C {} struct S(TBase, TDerived : TBase) {} S!(Object, C) a; 2) A type parameter with a type specialization followed by template parameter list: struct Fn(U) {} struct S(T: Fn!Arg, Arg) {} S!(Fn!int) a; 3) Following a type parameter, a value parameter of that type may appear: struct S(T, T value) {} S!(int, 4) a; The first two can also be combined: struct Fn(U) {} struct S(T1, T2: Fn!T3, T3 : T1) {} S!(int, Fn!int) a; However, it seems 3) only works with that specific type, modulo storage classes. No Foo!T, no void delegate(T). At any rate, the alias parameter is the way it's generally done, and is more flexible, so just leave it at that. -- Simen
Feb 20
parent Simon van Bernem <simon.vanbernem yahoo.de> writes:
Thanks! The alias solution works and is good enough for me. Also 
thanks for providing the code to typecheck the alias, I would 
have never been able to come up with that myself.
Feb 20