Как сделать членов структуры доступными по-разному

Я хочу иметь структуру 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 ответа

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

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

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

Если мы добавим token_reference struct и некоторые глобальные (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 и еще один параметр.

Посмотрите на 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 ); } );
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;
}
Другие вопросы по тегам