Re: Search elemnt in Compile-time Argument List of strings

2016-07-27 Thread ag0aep6g via Digitalmars-d-learn

On 07/26/2016 09:30 PM, ParticlePeter wrote:

So how can I achieve my goal the right way?


Here's one with CTFE:


void processMember(T, ignore...)()
{
import std.algorithm: canFind, filter;
import std.meta: aliasSeqOf;

enum selectedMembers = aliasSeqOf!(
[__traits(allMembers, T)].filter!(m => ![ignore].canFind(m))
);

foreach (member; selectedMembers)
{
/* process member here, generate e.g. setter function as string 
mixin */

}
}



Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread Steven Schveighoffer via Digitalmars-d-learn

On 7/26/16 4:58 PM, ParticlePeter wrote:

On Tuesday, 26 July 2016 at 20:18:48 UTC, Steven Schveighoffer wrote:


void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) { // this is a
compile-time list, so it's a static foreach.
foreach(i, arg; ignore ){ // i is the index into the ignore tuple
  static if( arg == member ) break; // break out of the foreach
loop, need to ignore it.
  else static if(i + 1 == arg.length) // this is the last element!
  {
  // process member here, generate e.g. setter function as string
mixin
  }
}
  }
}


There is one problem with this approach, ignore might be empty (I should
have mentioned it). Would you know a workaround for that case as well?


Hm... good point :)

Here is a workaround:

foreach(i, arg; AliasSeq!(ignore, "SENTINEL"))
   static if(i == ignore.length)
   {
  // process, it's good
   }
   else static if(arg == member) break;

-Steve


Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn

On Tuesday, 26 July 2016 at 21:20:18 UTC, ParticlePeter wrote:
...

First of all there seems to be a typo, it should not be:
  else static if(i + 1 == arg.length)

ignore must be used instead of arg, as arg.length is the length 
of a string:

  else static if(i + 1 == ignore.length)

if ignore is empty, its length is 0, so that the statement 
would always evaluate to false.


Btw, if ignore is not empty, only the last element (arg) is 
skipped.



Test:
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
foreach( i, arg; ignore ) { // i is the index into the ignore 
tuple
  static if( arg == member ) break; // break out of the 
foreach loop, ...
  else static if( i + 1 == ignore.length ) { // this is the 
last element!

pragma( msg, "processing ", member );
  }
}
  }
}

struct Foo { float a, b, c, d; }

int main() {
  processMember!( Foo );// nada
  processMember!( Foo, "c" );   // works
  processMember!( Foo, "c", "b" );  // skips only b
}





Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn

On Tuesday, 26 July 2016 at 21:01:19 UTC, Ali Çehreli wrote:

On 07/26/2016 01:58 PM, ParticlePeter wrote:
On Tuesday, 26 July 2016 at 20:18:48 UTC, Steven Schveighoffer 
wrote:

...

void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) { // this is a
compile-time list, so it's a static foreach.
foreach(i, arg; ignore ){ // i is the index into the 
ignore tuple
  static if( arg == member ) break; // break out of the 
foreach

loop, need to ignore it.
  else static if(i + 1 == arg.length) // this is the last 
element!

  {
  // process member here, generate e.g. setter function 
as string

mixin
  }
}
  }
}


There is one problem with this approach, ignore might be empty 
(I should
have mentioned it). Would you know a workaround for that case 
as well?


It should work for empty ignore. Can you show with a short 
example please.


Ali


First of all there seems to be a typo, it should not be:
  else static if(i + 1 == arg.length)

ignore must be used instead of arg, as arg.length is the length 
of a string:

  else static if(i + 1 == ignore.length)

if ignore is empty, its length is 0, so that the statement would 
always evaluate to false.


Btw, if ignore is not empty, only the last element (arg) is 
skipped.




Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread Ali Çehreli via Digitalmars-d-learn

On 07/26/2016 01:58 PM, ParticlePeter wrote:

On Tuesday, 26 July 2016 at 20:18:48 UTC, Steven Schveighoffer wrote:
...

void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) { // this is a
compile-time list, so it's a static foreach.
foreach(i, arg; ignore ){ // i is the index into the ignore tuple
  static if( arg == member ) break; // break out of the foreach
loop, need to ignore it.
  else static if(i + 1 == arg.length) // this is the last element!
  {
  // process member here, generate e.g. setter function as string
mixin
  }
}
  }
}


There is one problem with this approach, ignore might be empty (I should
have mentioned it). Would you know a workaround for that case as well?


It should work for empty ignore. Can you show with a short example please.

Ali



Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn
On Tuesday, 26 July 2016 at 20:18:48 UTC, Steven Schveighoffer 
wrote:

...

void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) { // this is a 
compile-time list, so it's a static foreach.
foreach(i, arg; ignore ){ // i is the index into the ignore 
tuple
  static if( arg == member ) break; // break out of the 
foreach loop, need to ignore it.
  else static if(i + 1 == arg.length) // this is the last 
element!

  {
  // process member here, generate e.g. setter function as 
string mixin

  }
}
  }
}


There is one problem with this approach, ignore might be empty (I 
should have mentioned it). Would you know a workaround for that 
case as well?


Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn
On Tuesday, 26 July 2016 at 20:18:48 UTC, Steven Schveighoffer 
wrote:

...
Thanks a lot for this really cool and detailed explanation 
(upvoting!).


It's a bit weird to work on these compile-time things, but they 
are so cool when you look at what is available in std.meta and 
std.traits :)


Agreed with each aspect. When I (just) read Philippe Sigaud's D 
Templates Tutorial I didn't get a thing. Important thing is 
getting your hands dirty, then it comes slowly.


















Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread Steven Schveighoffer via Digitalmars-d-learn

On 7/26/16 3:30 PM, ParticlePeter wrote:

I want to generate one function for any struct data member, but also
want to be able to skip few of the members. The first part works, but I
have some trouble with the skipping.

I pass the struct type and a Compile-time Argument List of strings as
template arguments to a template function, list all members of the
struct and compare each member to each element of the List. If the
member is in the List skip processing of that member. Pretty straight
forward ... should be.

// First approach doesn't work:
// Error: variable skip cannot be read at compile time
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
bool skip = false;
foreach( arg; ignore )
  skip = skip || ( arg == member );

static if( !skip ) {
  // process member here, generate e.g. setter function as string mixin
}
  }
}

// Second approach, get warnings for every skipped member
// and every line after the return statement:
// Warning: statement is not reachable
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
foreach( arg; ignore )
  static if( arg == member )
return;
// process member here, generate e.g. setter function as string mixin
  }
}

So how can I achieve my goal the right way?


You are doing it *almost* right.

What you need to remember is what is compile time, and what is runtime. 
In order to declare something is readable at compile-time, you need to 
have an expression that only involves compile-time constants. This means 
you need to process *all* the ignore's at once, or process the "end of 
the loop" after you haven't found it. Here is one way to do it:



void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) { // this is a 
compile-time list, so it's a static foreach.

foreach(i, arg; ignore ){ // i is the index into the ignore tuple
  static if( arg == member ) break; // break out of the foreach 
loop, need to ignore it.

  else static if(i + 1 == arg.length) // this is the last element!
  {
  // process member here, generate e.g. setter function as string mixin
  }
}
  }
}

Another way is to use std.meta.anySatisfy 
(http://dlang.org/phobos/std_meta.html#.anySatisfy), which can apply a 
template to each element in a compile-time list to see if any match:


template skipper(string target)
{
   enum shouldSkip(string s) = (s == target);
}

// replace your bool skip = ... with this:
enum skip = anySatisfy!(skipper!(member).shouldSkip, ignore);

It's a bit weird to work on these compile-time things, but they are so 
cool when you look at what is available in std.meta and std.traits :)


-Steve


Re: Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn

On Tuesday, 26 July 2016 at 19:30:18 UTC, ParticlePeter wrote:

// Second approach, get warnings for every skipped member
// and every line after the return statement:
// Warning: statement is not reachable
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
foreach( arg; ignore )
  static if( arg == member )
return;
// process member here, generate e.g. setter function as 
string mixin

  }
}

So how can I achieve my goal the right way?


I just realized that the second approach, despite the warnings, 
does not achieve its goal. The members are still forwarded. So I 
should rather ask how I could filter the members at all.


Search elemnt in Compile-time Argument List of strings

2016-07-26 Thread ParticlePeter via Digitalmars-d-learn
I want to generate one function for any struct data member, but 
also want to be able to skip few of the members. The first part 
works, but I have some trouble with the skipping.


I pass the struct type and a Compile-time Argument List of 
strings as template arguments to a template function, list all 
members of the struct and compare each member to each element of 
the List. If the member is in the List skip processing of that 
member. Pretty straight forward ... should be.


// First approach doesn't work:
// Error: variable skip cannot be read at compile time
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
bool skip = false;
foreach( arg; ignore )
  skip = skip || ( arg == member );

static if( !skip ) {
  // process member here, generate e.g. setter function as 
string mixin

}
  }
}

// Second approach, get warnings for every skipped member
// and every line after the return statement:
// Warning: statement is not reachable
void processMember( T, ignore... )() {
  foreach( member; __traits( allMembers, T )) {
foreach( arg; ignore )
  static if( arg == member )
return;
// process member here, generate e.g. setter function as 
string mixin

  }
}

So how can I achieve my goal the right way?