Strange alias behaviour in template arguments

Stefan Frijters via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Mar 3 14:53:35 PST 2015


On Tuesday, 3 March 2015 at 14:40:45 UTC, anonymous wrote:
> On Tuesday, 3 March 2015 at 13:42:09 UTC, Stefan Frijters wrote:
>> So this is a strange thing I ran into while trying to 
>> streamline some templates in my code, where fixed-length 
>> arrays are passed as runtime arguments. I started out by 
>> trying variant fun2(), which disappointingly didn't work. 
>> fun3() then did its job but I was suspicious and tried fun4() 
>> and fun(5), which also worked but shouldn't. Is this a bug or 
>> am I doing something bad?
>>
>> struct Connectivity(uint _d, uint _q) {
>>  enum d = _d; // Number of dimensions
>>  enum q = _q;
>> }
>>
>> alias d2q9 = Connectivity!(2,9);
>>
>> // Stores fixed-size array of base type T, and the length of 
>> the array is determined by the connectivity.
>> struct Field(T, alias c) {
>>  alias conn = c;
>>  T[conn.d] payload;
>>
>>  this(in T[conn.d] stuff) {
>>    payload = stuff;
>>  }
>> }
>>
>> // Ok
>> void fun(T)(T field) {
>>  pragma(msg, T);
>>  pragma(msg, T.conn);
>>  pragma(msg, T.conn.d);
>>  pragma(msg, T.conn.q);
>> }
>>
>> // cannot deduce function from argument types
>> void fun2(T)(T field, double[T.conn.d] foo) {
>>  pragma(msg, T);
>>  pragma(msg, T.conn);
>>  pragma(msg, T.conn.d);
>>  pragma(msg, T.conn.q);
>>  field.payload = foo;
>> }
>>
>> // Ok!
>> void fun3(T, alias d = T.conn.d)(T field, double[d] foo) {
>>  pragma(msg, T);
>>  pragma(msg, T.conn);
>>  pragma(msg, T.conn.d);
>>  pragma(msg, T.conn.q);
>>  pragma(msg, typeof(foo)); // 2, okay
>>  field.payload = foo;
>> }
>>
>> // Huh?
>> void fun4(T, alias d = T.conn.q)(T field, double[d] foo) {
>>  pragma(msg, T);
>>  pragma(msg, T.conn);
>>  pragma(msg, T.conn.d);
>>  pragma(msg, T.conn.q);
>>  pragma(msg, typeof(foo)); // expect 9, get 2
>>  field.payload = foo;
>> }
>>
>> // Huh?
>> void fun5(T, alias d = T.conn)(T field, double[d] foo) {
>>  pragma(msg, T);
>>  pragma(msg, T.conn);
>>  pragma(msg, T.conn.d);
>>  pragma(msg, T.conn.q);
>>  pragma(msg, typeof(foo)); // don't know what to expect, still 
>> get 2
>>  field.payload = foo;
>> }
>>
>> void main() {
>>  double[d2q9.d] foo;
>>  auto f = Field!(double, d2q9)(foo);
>>
>>  f.fun();         // Sure, this works
>>  // f.fun2(foo);  // Won't work without additional alias
>>  f.fun3(foo);     // Works, so are we happy?
>>  f.fun4(foo);     // No! This isn't supposed to work...
>>  f.fun5(foo);     // Nor this...
>> }
>>
>> Any thoughts?
>
> I don't know if there's a reason why fun2 doesn't work. I don't 
> see one.
>
> fun4 and fun5 work correctly. They are the same as fun3, just 
> with other default values for d. Those default values are not 
> used, because d is inferred from the argument to be 2. If you 
> pass a double[3], d is inferred to be 3 (and the compiler 
> complains on `field.payload = foo`).
>
> You can use a static assert or a template constraint to work 
> around fun2 not working:
>
> void fun6(T, size_t d)(T field, double[d] foo)
> {
>   static assert(d == T.conn.d);
>   ...
> }
> void fun7(T, size_t d)(T field, double[d] foo) if(d == T.conn.d)
> {
>   ...
> }

Ah, yes, I was misinterpreting the alias. fun7() would work for 
me, although it's a shame fun2() doesn't...

Cheers.


More information about the Digitalmars-d-learn mailing list