How to access members in different ways

I want to have a token structure that has start / end pairs for position, sentence and paragraph information. I also want participants to be available in different ways: as a start / end pair and individually. Given:

 struct token { struct start_end { int start; int end; }; start_end pos; start_end sent; start_end para; typedef start_end token::*start_end_ptr; }; 

I can write a function, say distance() , which calculates the distance between any of the three start / end pairs, such as:

 int distance( token const &i, token const &j, token::start_end_ptr mbr ) { return (j.*mbr).start - (i.*mbr).end; } 

and name it like this:

  token i, j; int d = distance( i, j, &token::pos ); 

which will return the distance from the pair pos . But I can also pass &token::sent or &token::para , and it does what I want. Therefore, the function is flexible.

However, now I also want to write a function, say max() , which calculates the maximum value for all pos.start or all pos.end or all sent.start , etc.

If I add:

  typedef int token::start_end::*int_ptr; 

I can write a function like:

 int max( list<token> const &l, token::int_ptr p ) { int m = numeric_limits<int>::min(); for ( list<token>::const_iterator i = l.begin(); i != l.end(); ++i ) { int n = (*i).pos.*p; // NOT WHAT I WANT: It hard-codes 'pos' if ( n > m ) m = n; } return m; } 

and name it like this:

  list<token> l; l.push_back( i ); l.push_back( j ); int m = max( l, &token::start_end::start ); 

However, as stated in the comment above, I do not want to hardcode the pos . I want the flexibility of the available start or end any of pos , sent or para to be passed as a parameter to max() .

I tried several things to get this to work (tried using unions, anonymous unions, etc.), but I can't come up with a data structure that allows flexibility in both ways when saving each value only once.

Any ideas how to arrange the token structure so that I can have what I want?


Attempted clarification

Given the structure of integer pairs, I want to be able to "slice" the data in two different ways:

  • Passing a pointer to an element of a specific start / end pair, so that the called function works on any pair, not knowing which pair. The caller decides which pair.
  • By passing a pointer to an element of a particular int (i.e. only one int any pair), so the function being called works on any int , not knowing what int , or which pair said int from. The caller decides which int which pair.

Another example for the latter would be the summation of, say, total para.end or total sent.start .

Also, and what's important: for # 2 above, I would ideally want to pass only one member pointer to reduce the load on the caller. Therefore, I am trying to understand something using alliances.

For # 2, the structure will be optimally laid out like this:

 struct token2 { int pos_start; int pos_end; int sent_start; int sent_end; int para_start; int para_end; }; 

The trick is token and token2 somehow superimposed on the union , but this is not obvious if / how to do it and still satisfy the available requirements.

+4
source share
4 answers

Just give it a try.

 int max( list<token> const &l, token::int_ptr p, token::start_end_ptr mbr ) { int m = numeric_limits<int>::min(); for ( list<token>::const_iterator i = l.begin(); i != l.end(); ++i ) { int n = ((*i).*mbr).*p; if ( n > m ) m = n; } return m; } 
+2
source

I am based on the answer baol gave:

If we add a token_reference structure and some global (ick!) Variables, we can have this:

 struct token_reference { token::start_end_ptr start_end_ptr; token::int_ptr int_ptr; }; token_reference pos_start = { &token::pos, &token::start_end::start }; token_reference pos_end = { &token::pos, &token::start_end::end }; token_reference sent_start = { &token::sent, &token::start_end::start }; token_reference sent_end = { &token::sent, &token::start_end::end }; token_reference para_start = { &token::para, &token::start_end::start }; token_reference para_end = { &token::para, &token::start_end::end }; int max( std::list<token> const &l, token_reference& ref ) { return max(l,ref.start_end_ptr,ref.int_ptr); } 

called like this:

 tokenList aList; int value = max(aList,pos_start); 

you get a function that takes list and another parameter.

+1
source

Take a look at boost::bind or boost::lambda libraries. Or, if you can use a compiler with C ++ 0x support, you can use some of the new functions instead of manually binding member attributes. And then you can use the algorithms provided in STL ...

In any case, this can do what you want (I did not even find the time to try to compile it so that it could not compile):

 int max( list<token> const &l, token::start_end_ptr m, token::int_ptr p ) { int m = numeric_limits<int>::min(); for ( list<token>::const_iterator i = l.begin(); i != l.end(); ++i ) { int n = (*i).*m.*p; if ( n > m ) m = n; } return m; } int main() { list<token> tks; int x = max( tks, &token::pos, &token::start_end::start ); } 

Please note that this is not a completely understandable path to flexibility: you bind the algorithm to the types token , token::start_end and int ...

C ++ 0x:

 list <token> tks; int the_max = 0; for_each( tks.begin(), tks.end(), [&the_max]( token const & t ) { the_max = max( the_max, t.pos.start ); } ); 
0
source
 struct start_end { int x; int y; }; struct pairs { struct start_end a; struct start_end b; } 

Is the idea to crop data dynamically for X or Y?

  int distance(start_end m, start_end n, int member_offset){ int val_a = *(&m + member_offset); int val_b = *(&n + member_offset); int distance = val_b - val_a; return distance; } 
0
source

Source: https://habr.com/ru/post/1305791/


All Articles