Thread overview
Confused by struct constructors
Jan 23, 2010
Simen kjaeraas
Jan 23, 2010
bearophile
Jan 23, 2010
Philippe Sigaud
Jan 24, 2010
Simen kjaeraas
Jan 24, 2010
Philippe Sigaud
January 23, 2010
In attempting to create a function to initialize any array of structs in a simple manner, I created this code:

void fillArr( uint n, T, U... )( ref T[] arr, U args ) {
  arr[0] = T( U[0..n] );
  static if ( U.length > n ) {
    fillArr!( n )( arr[ 1..$ ], args[ n..$ ] );
  }
}

T[] initArray( T, uint n = U.length, U... )( U args ) if ( n > 0 ) {
  static if (
//      ( __traits( compiles, T( args[ 0..n ] ) ) ) && // Same as below. Added for completeness.
      ( is( typeof( T( args[ 0..n ] ) ) ) ) &&  // If we can instantiate a struct with this
      ( U.length % n == 0 )                     // and it matches the number of arguments,
      ) {
    T[] result = new T[ U.length / n ];         // Create an array
    fillArr!( n )( result, args );              // and fill it.
    return result;
  } else {
    return initArray!( T, n-1, U )( args );     // Didn't work. Try another parameter count.
  }
}

However, upon testing it with this code:

struct S {
  int n;
  string s;
}
auto s = initArray!( S )( 1, "a", 2, "b", 3, "c" );

I get this error:

foo.d(34): Error: cannot implicitly convert expression ((int _param_1, string _param_2)) of type (int _param_1, string _param_2) to int


The problem is apparently on this line:
  arr[0] = T( U[0..n] );
Though I am confuzzled as to why it does not work ( it works in initArray, line 2 ). Any ideas?

-- 
Simen
January 23, 2010
Simen kjaeraas:

> In attempting to create a function to initialize any array of structs in a
> simple manner,
> ...
> auto s = initArray!( S )( 1, "a", 2, "b", 3, "c" );

That syntax is not useful, if you have few more structs or fields you are lost in the soup of commas and items..

Bye,
bearophile
January 23, 2010
On Sat, Jan 23, 2010 at 14:44, Simen kjaeraas <simen.kjaras@gmail.com>wrote:

> In attempting to create a function to initialize any array of structs in a simple manner, I created this code:
>
> void fillArr( uint n, T, U... )( ref T[] arr, U args ) {
>  arr[0] = T( U[0..n] );
>  static if ( U.length > n ) {
>    fillArr!( n )( arr[ 1..$ ], args[ n..$ ] );
>  }
> }
>

U is a type . U[0..n] is also a type. You should write:

arr[0]  = T(args[0..n]);


Maybe you could also use S.tupleof.length to get the number of fields in S (or maybe there is a __traits which gives this) and avoid the recursion in initArray:


void fillArr( T, U... )( ref T[] arr, U args ) {
 arr[0] =  T(args[0..T.tupleof.length]) ;
 static if ( U.length > T.tupleof.length ) {
   fillArr( arr[ 1..$ ], args[ T.tupleof.length..$ ] );
 }
}

T[] initArray( T, U... )( U args )
    if ( U.length > 0
    && (is(typeof( T( args[ 0..T.tupleof.length ] ) ) ) )
    && ( U.length % T.tupleof.length == 0 ))
{
   T[] result = new T[ U.length / T.tupleof.length ];         // Create an
array
   fillArr( result, args );              // and fill it.
   return result;
}

Philippe


January 24, 2010
On Sat, 23 Jan 2010 18:09:26 +0100, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:

> On Sat, Jan 23, 2010 at 14:44, Simen kjaeraas <simen.kjaras@gmail.com>wrote:
>
>> In attempting to create a function to initialize any array of structs in a
>> simple manner, I created this code:
>>
>> void fillArr( uint n, T, U... )( ref T[] arr, U args ) {
>>  arr[0] = T( U[0..n] );
>>  static if ( U.length > n ) {
>>    fillArr!( n )( arr[ 1..$ ], args[ n..$ ] );
>>  }
>> }
>>
>
> U is a type . U[0..n] is also a type. You should write:

Thank you! Darn, I should have been able to see that.

> Maybe you could also use S.tupleof.length to get the number of fields in S

Yeah, I could. However, S might use a different constructor, taking a
different number of arguments.

As for bearophile's concerns:
  struct simpleTuple( T... ) {
    T payload;
  }

  simpleTuple!( T ) ຕ( T... )( T args ) {
    return simpleTuple!( args );
  }

  T[] initArray( T, U... )( U args ) if ( is( typeof( T( args[0].tupleof ) ) ) && allSame!( U ) ) {
    T[] result = new T[ U.length ];
    foreach ( i, arg; args ) {
      result[ i ] = T( arg.tupleof );
    }
    return result;
  }

  struct S {
    int n;
    string s;
  }

  auto s = initArray!( S )( ຕ( 1, "a" ), ຕ( 2, "b" ), ຕ( 3, "c" ) );

If ຕ is too hard to type, choose another short name.

-- 
Simen
January 24, 2010
 auto s = initArray!( S )( ຕ( 1, "a" ), ຕ( 2, "b" ), ຕ( 3, "c" ) );

>
> If ຕ is too hard to type, choose another short name.
>

Nice looking character. Indian, hebrew?

When I want an almost non-visible char, I tend tu use _, just _.

Philippe