Как сделать членов структуры доступными по-разному - PullRequest
4 голосов
/ 01 апреля 2010

Я хочу иметь структуру token, в которой есть пары начала / конца для информации о положении, предложении и абзаце. Я также хочу, чтобы участники были доступны двумя разными способами: в качестве начальной / конечной пары и индивидуально. Дано:

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;
};

Я могу написать функцию, скажем distance(), которая вычисляет расстояние между любой из трех пар start / end, например:

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

и назовите это как:

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

, который вернет расстояние пары pos. Но я также могу передать &token::sent или &token::para, и он делает то, что я хочу. Следовательно, функция является гибкой.

Однако теперь я также хочу написать функцию, скажем, max(), которая вычисляет максимальное значение всех pos.start или всех pos.end или всех sent.start и т. Д.

Если я добавлю:

  typedef int token::start_end::*int_ptr;

Я могу написать функцию как:

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;
}

и назовите это как:

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

Однако, как указано в комментарии выше, я не хочу жестко кодировать pos. Мне нужна гибкость доступа к start или end любого из pos, sent или para, которые будут переданы в качестве параметра max().

Я пробовал несколько вещей, чтобы заставить это работать (пытался использовать союзы, анонимные союзы и т. Д.), Но я не могу придумать структуру данных, которая обеспечивает гибкость в обоих направлениях, сохраняя каждое значение только один раз.

Есть идеи, как организовать структуру token, чтобы я мог получить то, что хочу?


Попытка разъяснения

Учитывая структуру пар целых чисел, я хочу иметь возможность "разрезать" данные двумя различными способами:

  1. Путем передачи указателя на член конкретной пары начало / конец, чтобы вызываемая функция работала с любой парой, не зная, какая пара. Вызывающий абонент решает, какая пара.
  2. Передав указатель на член определенной int (т. Е. Только один int любой пары), чтобы вызываемая функция работала с любым int, не зная, какой int или какая пара сказала, что int от. Вызывающий абонент решает, какая int из какой пары.

Другим примером для последнего будет суммировать, скажем, все para.end или все sent.start.

Кроме того, и это важно: для # 2 выше, в идеале, я бы хотел передать только один указатель на член, чтобы уменьшить нагрузку на вызывающего. Поэтому я пытаюсь что-то выяснить, используя союзы.

Для # 2 структура будет оптимально выстроена следующим образом:

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

Хитрость заключается в том, чтобы token и token2 как-то перекрывались с union, но неясно, можно ли / как это сделать, и при этом удовлетворить доступные требования.

Ответы [ 4 ]

2 голосов
/ 01 апреля 2010

Просто попробуй.

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;                                                                     
}                                
1 голос
/ 02 апреля 2010

Я строю на ответе Баол дал:

Если мы добавим token_reference структуру и некоторые глобальные (ick!) Переменные, мы можем получить это:

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);
}

называется так:

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

вы получаете функцию, принимающую list и еще один параметр.

0 голосов
/ 01 апреля 2010
struct start_end {
    int x;
    int y;
};
struct pairs {
    struct start_end a;
    struct start_end b;
}

Так что же, идея состоит в том, чтобы разрезать данные для динамической обработки по X или 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 голосов
/ 01 апреля 2010

Взгляните на библиотеки boost::bind или boost::lambda. Или, если вы можете использовать компилятор с поддержкой C ++ 0x, вы можете использовать некоторые новые функции вместо того, чтобы вручную связывать атрибуты члена. И тогда вы можете использовать алгоритмы, представленные в STL ...

В любом случае это может делать то, что вы хотите (я даже не потратил время, чтобы попытаться скомпилировать его, так что он может не скомпилироваться):

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 );
}

Обратите внимание, что это не путь к гибкости, хорошо понятый: вы привязываете алгоритм к типам token, token::start_end и 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 ); } );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...